FileShare文件读写锁解决“文件XXX正由另一进程使用,因此该进程无法访问此文件”(转)
开发过程中,我们往往需要大量与文件交互,读文件,写文件已成家常便饭,本地运行完美,但一上到投产环境,往往会出现很多令人措手不及的意外,或开发中的烦恼,因此,我对普通的C#文件操作做了一次总结,问题大部分如下:
1:写入一些内容到某个文件中,在另一个进程/线程/后续操作中要读取文件内容的时候报异常,提示 System.IO.IOException: 文件“XXX”正由另一进程使用,因此该进程无法访问此文件。
2:在对一个文件进行一些操作后(读/写),随后想追加依然报System.IO.IOException: 文件“XXX”正由另一进程使用,因此该进程无法访问此文件。次问题与1相似。
3:对一个文件进行一些操作后,想删除文件,依然报System.IO.IOException: 文件“XXX”正由另一进程使用,因此该进程无法访问此文件。
看到这些,有经验的同学应该就会说资源没被释放掉,但也存在如下可能性。我们对文件的操作非常频繁,所以写了特定的操作类/组件来维护文件之间的操作,知道特定的时刻才结束,常见的如日志,随着程序的启动便开始写日志,直到程序关闭。但其中也存在我们需要提供一个特殊的操作(读/写/删除)来操作文件,例如我们需要提供一个日志查看器来查看当前日志或所有日志,这时,便无可避免的发生了以上的问题。
static void WriteFile(FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
{
Console.WriteLine("please input your content.");
var content = Console.ReadLine();
FileStream fs = new FileStream(FILEPATH, fileMode, fileAccess, fileShare);
var buffer = Encoding.Default.GetBytes(content);
fs.Write(buffer, 0, buffer.Length);
fs.Flush();
}
首先,我声明了一个写文件方法,并调用它,它将我输入的内容写入指定的文件当中。
WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
Console.ReadKey();


但是,在写文件操作结束之后,我并没有释放掉文件流的资源。所以,此时会对文件造成一个锁。我尝试在windows中删除它。

很明显我无法删除掉这个文件,接下来,我尝试读取它。
static void ReadFile(FileAccess fileAccess, FileShare fileShare)
{
FileStream fs = new FileStream(FILEPATH, FileMode.Open, fileAccess, fileShare);
var buffer = new byte[fs.Length];
fs.Position = 0;
fs.Read(buffer, 0, buffer.Length);
Console.WriteLine(Encoding.Default.GetString(buffer));
}
我实现了一个读文件方法,并调用了它。
WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
ReadFile(FileAccess.Read, FileShare.Read);
一切都很简单,访问模式为只读,这样应该就不会与上面的写锁进行冲突!

但是,结果并非我们所预想的那样,为什么会提示无法访问?回想一下,在前面,我用windows的记事本打开了这个文件,并没有提示说文件被锁定,我也的确能访问,那为何到了程序里就无法访问了呢?或许,我们应该把重点放在FileMode,FileAccess,FileShare这三个枚举身上,说不定就是它们搞的鬼。
FileMode
MSDN上的解释是指定操作系统打开文件的方式,我想这个应该不需要解释了,大家平时用得比较多了。MSDN的表格也很好的阐述了各个枚举值的作用,我就不在解释了。
FileAccess
定义用于文件读取、写入或读取/写入访问权限的常数。

这个枚举也用得比较多了,描述也很通俗易懂,我也不便再解释了。^_^!
FileShare
相信这个枚举类型大家会比较陌生,甚至有同学见都没见过(惭愧的是,我也是才认识它没多久),陌生归陌生,但它的作用力也是不可低估,只是.Net帮我们把它封装得比较好,以至于我们一度认为它不是什么重要角色。好吧,进入主题!
包含用于控制其他 FileStream 对象对同一文件可以具有的访问类型的常数。这句话是什么意思呢?说实话,我现在看句话还是觉得很纠结,相信很多同学看到也是一头雾水,没关系,我们先跳过!

看它的成员描述,和FileAccess很是相似,那我们就尝试着来揭开它暂时神秘的面纱吧!
FileShare.Read
从字面上的意思,我们可以理解为首先打开一个文件之后(资源未释放),我们可以再用只读的方式读取文件从而不会抛出文件无法访问的异常。利用刚才实现的方法,可以轻易的再完成这个实验:

这是什么回事?不是都设置成已读了吗?或许只能在读文件的时候才能设置为只读共享。我们再尝试一下:
ReadFile(FileAccess.Read, FileShare.Read);
ReadFile(FileAccess.Read, FileShare.Read);

这次的确是能在第一次没释放资源时再读,那我们再试试能否在设置只读共享后写文件:
ReadFile(FileAccess.Read, FileShare.Read);
WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);

首先正确的读出了文件的内容,但当我尝试写入一些内容的时候却又报错了。那么,根据以上的实验,就可以得知这个只读的共享只有是在连续读取文件才有效!
FileShare.Write
结合Read的经验,字面上的意思应该可以理解为,只有在写文件时设置共享方式为Write,随后才能继续写入文件,否则会抛出异常。这里比较好玩的时,设置Write之后,万能的Window记事本也打不开文件了。

FileShare.ReadWrite
有了以上的经验,从字面上理解,可以认为这个ReadWrite一定是结合了Read和Write的特性。那到底它有什么用呢?上面我们知道,在读文件设置Read共享能继续读而不能写,在写文件时设置Write共享则能继续写而不能读,但是当我们设置了写共享后并想读取文件时怎么办?只能先释放资源再重新加载了吗?不需要,ReadWrite就是为此而生的。
WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
ReadFile(FileAccess.Read, FileShare.ReadWrite);

不过这里写文件的时候并不允许把共享设置成Write,否则读文件时用ReadWrite则无效(报异常),但都设置为ReadWrite可以。这一定,便可以解决很多日常开发中的烦恼。
FileShare.None/FileShare.Delete
有了上面的经验,相信这两个你也很容易的就理解了,None则为不允许后续有任何操作,而Delete则是允许你随后进行删除操作。
FileShare文件读写锁解决“文件XXX正由另一进程使用,因此该进程无法访问此文件”(转)的更多相关文章
- FileShare枚举的使用(文件读写锁)
开发过程中,我们往往需要大量与文件交互,但往往会出现很多令人措手不及的意外,所以对普通的C#文件操作做了一次总结,问题大部分如下: 1:写入一些内容到某个文件中,在另一个进程/线程/后续操作中要读取文 ...
- FileShare枚举的使用(文件读写锁) - (转载)
开发过程中,我们往往需要大量与文件交互,但往往会出现很多令人措手不及的意外,所以对普通的C#文件操作做了一次总结,问题大部分如下: 写入一些内容到某个文件中,在另一个进程/线程/后续操作中要读取文件内 ...
- Linux多线程实践(6) --Posix读写锁解决读者写者问题
Posix读写锁 int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *rest ...
- C#使用读写锁解决多线程并发写入文件时线程同步的问题
读写锁是以 ReaderWriterLockSlim 对象作为锁管理资源的,不同的 ReaderWriterLockSlim 对象中锁定同一个文件也会被视为不同的锁进行管理,这种差异可能会再次导致文件 ...
- php文件读写锁
$file = fopen("test.txt", $fileOpenMode); flock($file, $lockMode) or die("Can't lock& ...
- /bin/sh^M: bad interpreter:没有那个文件或目录解决
/bin/sh^M: bad interpreter:没有那个文件或目录解决 执行脚本时发现如下错误: /bin/sh^M: bad interpreter: 没有那个文件或目录 错误分析: ...
- java多线程:并发包中ReentrantReadWriteLock读写锁的原理
一:读写锁解决的场景问题--->数据的读取频率远远大于写的频率的场景,就可以使用读写锁.二:读写锁的结构--->用state一个变量.将其转化成二进制,前16位为高位,标记读线程获取锁的次 ...
- 源码分析:ReentrantReadWriteLock之读写锁
简介 ReentrantReadWriteLock 从字面意思可以看出,是和重入.读写有关系的锁,实际上 ReentrantReadWriteLock 确实也是支持可重入的读写锁,并且支持公平和非公平 ...
- 用读写锁三句代码解决多线程并发写入文件 z
C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...
随机推荐
- python 元类与定制元类
1:元类 元类:类的创建与管理者 所有类的元类是type class a: pass print(type(a)) 结果:<class 'type'> 2:定制元类 类的实例化过程:(可看 ...
- 关于.net根目录路径的问题
今天做了一个项目,用了url重写,但是在本地目录是localhost/BK/index.aspx,而其他目录也必须带bk,不带的话就找不到页面,(iis里正常) 应该主目录去掉bk,设置方法,右击网站 ...
- DateTime对象反序列化的那些事
今天在Android的Json反序列化过程中,Date类型无法转化成自己想要的格式,鉴于之前在C#的反序列话中也遇到过这个问题,解决的同时,顺手做个总结,供自己及需要的人日后查阅. 将Da ...
- cell高度自动适应文章内容
效果: 描述:表视图中生成多个不同的cell,cell的高度跟文字内容的多少有关 要求:需要自己在网上下载一个plis文件,然后修改两个标题 一 : 创建工程文件UIAutomaticCellHeig ...
- C#Socket 案例
服务器端 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; ...
- 自定义函数标签(JSTL)
创建自定义函数标签步骤: 1.创建类,并且方法只能是静态 public static void operation(calculator cal) 2.书写tld <taglib xmlns=& ...
- js formatString 格式化字符串
/* 函数:格式化字符串 参数:str:字符串模板: data:数据 调用方式:formatString("api/values/{id}/{name}",{id:101,name ...
- 会话控制session,cookie(0521)
简单介绍: 一.什么是session? 1. 定义: Session,在计算机中,尤其是在网络应用中,称为“会话”.在计算机专业术语中,Session是指一个终端用户与交互系统进行通信的时间间隔,通常 ...
- Android再学习-便签开发小结-20141119
这几天的便签开发,首先遇到的问题就是数据库操作问题.现在已经可以读写数据库了,并能将数据放在正确的位置显示. 专门建立了一个数据库操作的包,命名为"...database".新建一 ...
- (转载)MVC 4.0 PartialView()与View()真的一样吗?
转载自:http://www.cnblogs.com/lori/ 当我们使用razor作为页面引擎时,它的视图文件扩展名为cshtml或者vbshtml,而之前作为分部视图的ascx文件,进行razo ...