开发过程中,我们往往需要大量与文件交互,但往往会出现很多令人措手不及的意外,所以对普通的C#文件操作做了一次总结,问题大部分如下:

1:写入一些内容到某个文件中,在另一个进程/线程/后续操作中要读取文件内容的时候报异常,提示 System.IO.IOException: 文件“XXX”正由另一进程使用,因此该进程无法访问此文件。

2:在对一个文件进行一些操作后(读/写),随后想追加依然报System.IO.IOException: 文件“XXX”正由另一进程使用,因此该进程无法访问此文件。次问题与1相似。

3:对一个文件进行一些操作后,想删除文件,依然报System.IO.IOException: 文件“XXX”正由另一进程使用,因此该进程无法访问此文件。

看到这些,有经验的同学应该就会说资源没被释放掉,但也存在如下可能性。我们对文件的操作非常频繁,所以写了特定的操作类/组件来维护文件之间的操作,知道特定的时刻才结束,常见的如日志,随着程序的启动便开始写日志,直到程序关闭。但其中也存在我们需要提供一个特殊的操作(读/写/删除)来操作文件,例如我们需要提供一个日志查看器来查看当前日志或所有日志,这时,便无可避免的发生了以上的问题。

首先声明一个写文件方法。

  1. static void WriteFile(FileMode fileMode, FileAccess fileAccess, FileShare fileShare)
  2. {
  3. Console.WriteLine("please input your content.");
  4. var content = Console.ReadLine();
  5. FileStream fs = new FileStream(FILEPATH, fileMode, fileAccess, fileShare);
  6. var buffer = Encoding.Default.GetBytes(content);
  7. fs.Write(buffer, , buffer.Length);
  8. fs.Flush();
  9. }

调用上面的方法,将输入内容写入指定的文件当中,用记事本打开log.txt可看到刚才输入的内容。

  1. WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
  2. Console.ReadKey();

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

很明显系统无法删除掉这个文件,接下来再尝试读取它。

  1. static void ReadFile(FileAccess fileAccess, FileShare fileShare)
  2. {
  3. FileStream fs = new FileStream(FILEPATH, FileMode.Open, fileAccess, fileShare);
  4. var buffer = new byte[fs.Length];
  5. fs.Position = ;
  6. fs.Read(buffer, , buffer.Length);
  7. Console.WriteLine(Encoding.Default.GetString(buffer));
  8. }

实现了一个读文件方法,并调用了它。

  1. WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
  2. ReadFile(FileAccess.Read, FileShare.Read);

一切都很简单,访问模式为只读,这样应该就不会与上面的写锁进行冲突。

但是,结果并非我们所预想的那样,为什么会提示无法访问?回想一下,在前面用windows的记事本打开了这个文件,并没有提示说文件被锁定,的确也能访问,那为何到了程序里就无法访问了呢?或许,我们应该把重点放在FileModeFileAccessFileShare这三个枚举变量上,说不定那就是解决问题的关键所在。

FileMode

MSDN上的解释是指定操作系统打开文件的方式,我想这个应该不需要解释了,大家平时用得比较多了。MSDN的表格也很好的阐述了各个枚举值的作用,我就不在解释了。

FileAccess

定义用于文件读取、写入或读取/写入访问权限的常数。这个枚举用得比较多,描述也很通俗易懂。

FileShare

相信这个枚举类型大家会比较陌生,甚至有同学见都没见过(惭愧的是,我也是才认识它没多久),陌生归陌生,但它的作用却是不可低估,只是微软帮我们把它封装得比较好,以至于我们一度认为它不是什么重要角色。好吧,进入主题!

包含用于控制其他 FileStream 对象对同一文件可以具有的访问类型的常数。这句话是什么意思呢?说实话,我现在看句话还是觉得很纠结,相信很多同学看到也是一头雾水,没关系,先跳过!

看它的成员描述,和FileAccess很是相似,那我们就尝试着来揭开它暂时神秘的面纱。

FileShare.Read

从字面上的意思,我们可以理解为首先打开一个文件之后(资源未释放),我们可以再用只读的方式读取文件从而不会抛出文件无法访问的异常。利用刚才实现的方法,可以轻易地验证我们的猜想:

  1. WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
  2. ReadFile(FileAccess.Read, FileShare.Read);

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

  1. ReadFile(FileAccess.Read, FileShare.Read);
  2. ReadFile(FileAccess.Read, FileShare.Read);

这次的确是能在第一次没释放资源时再读,那我们再试试能否在设置只读共享后写文件:

  1. ReadFile(FileAccess.Read, FileShare.Read);
  2. WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);

首先正确的读出了文件的内容,但当尝试写入一些内容时却又报错了。那么,根据以上的实验,就可以得知只读共享只有在连续读取文件才有效!写入文件后再读取或者读取文件后再写入都会抛异常

FileShare.Write

结合Read的经验,字面上的意思应该可以理解为,只有在写文件时设置共享方式为Write,随后才能继续写入文件,否则会抛出异常。测试的时候发现当设置共享方式为Write之后,万能的Window记事本也打不开文件了。

FileShare.ReadWrite

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

  1. WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
  2. ReadFile(FileAccess.Read, FileShare.ReadWrite);

注意:写文件的时候并不允许把共享设置成Write,否则读文件时用ReadWrite则无效(报异常),但都设置为ReadWrite可以。

FileShare.None/FileShare.Delete

有了上面的经验,这两个就很容易的就理解了,None则为不允许后续有任何操作,而Delete则是允许随后进行删除操作。

黑箱子里的内容

对于文件操作,我们平常使用的比较多的可能是以下几种:

  1. File.AppendAllText("......");
  2. File.AppendAllLines(...);
  3. File.AppendText(...);
  4. FileStream fs = new FileStream(path, FileAccess.Write);
  5. fs.Write(....);

实际上它们也是在内部初始化了FileMode/FileAccess/FileShare,例如File的静态方法最后都会生成一个Stream实例,其中便调用了私有方法CreateFile

尾声

现在,我们明白了,其实FileShare就是控制文件流的“访问权限”,当然,这仅仅是入门的文件操作,自己做了笔记,也希望能给大家带来帮助,高级篇园子里已经有不少前辈写了文件读写锁方面的文章,感兴趣的同学可有搜索一下,前去观摩!

转自:空逸云
出处:http://kongyiyun.cnblogs.com

FileShare枚举的使用(文件读写锁)的更多相关文章

  1. FileShare枚举的使用(文件读写锁) - (转载)

    开发过程中,我们往往需要大量与文件交互,但往往会出现很多令人措手不及的意外,所以对普通的C#文件操作做了一次总结,问题大部分如下: 写入一些内容到某个文件中,在另一个进程/线程/后续操作中要读取文件内 ...

  2. FileShare文件读写锁解决“文件XXX正由另一进程使用,因此该进程无法访问此文件”(转)

    开发过程中,我们往往需要大量与文件交互,读文件,写文件已成家常便饭,本地运行完美,但一上到投产环境,往往会出现很多令人措手不及的意外,或开发中的烦恼,因此,我对普通的C#文件操作做了一次总结,问题大部 ...

  3. php文件读写锁

    $file = fopen("test.txt", $fileOpenMode); flock($file, $lockMode) or die("Can't lock& ...

  4. 用读写锁三句代码解决多线程并发写入文件 z

    C#使用读写锁三句代码简单解决多线程并发写入文件时提示“文件正在由另一进程使用,因此该进程无法访问此文件”的问题 在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三 ...

  5. C#使用读写锁三行代码简单解决多线程并发写入文件时线程同步的问题

    (补充:初始化FileStream时使用包含文件共享属性(System.IO.FileShare)的构造函数比使用自定义线程锁更为安全和高效,更多内容可点击参阅) 在开发程序的过程中,难免少不了写入错 ...

  6. C#使用读写锁解决多线程并发写入文件时线程同步的问题

    读写锁是以 ReaderWriterLockSlim 对象作为锁管理资源的,不同的 ReaderWriterLockSlim 对象中锁定同一个文件也会被视为不同的锁进行管理,这种差异可能会再次导致文件 ...

  7. 让C#轻松实现读写锁分离

    ReaderWriterLockSlim 类 表示用于管理资源访问的锁定状态,可实现多线程读取或进行独占式写入访问. 使用 ReaderWriterLockSlim 来保护由多个线程读取但每次只采用一 ...

  8. 可重入锁 公平锁 读写锁、CLH队列、CLH队列锁、自旋锁、排队自旋锁、MCS锁、CLH锁

    1.可重入锁 如果锁具备可重入性,则称作为可重入锁. ========================================== (转)可重入和不可重入 2011-10-04 21:38 这 ...

  9. 锁的封装 读写锁、lock

    最近由于项目上面建议使用读写锁,而去除常见的lock锁.然后就按照需求封装了下锁.以简化锁的使用.但是开发C#的童鞋都知道lock关键字用起太方便了,但是lock关键字不支持超时处理.很无奈,为了实现 ...

随机推荐

  1. 警惕多iframe下的同名id引起的诡异问题

    遇到个诡异bug,虽然bug中套bug,忽略次要bug,其中最诡异最典型的现象是多行window.top.$("#id")取值操作,其中有一行却取不到值.这个着实让我费解.因为用到 ...

  2. DevOps Workshop 研发运维一体化第一场(微软亚太研发集团总部)

    准备了近两周,写了大量的操作手册,设计了大量的动手实验场景,终于在中关村的微软大厦完成了两天的DevOps培训. 最初报名160人,按照之前的培训经验,一般能到一半就不错了,没想到这次现场登记人员就超 ...

  3. unix automake 使用,快速生成你的Makefile

    使用automake快速生成编译的Makefile 1,确保自己装有的软件automake autoconf 2, 1)执行autoscan 并将生成的configure.scan重命名为config ...

  4. Eclipse汉化后怎么改回英文版(可切换中英文)

    Eclipse汉化后怎么改回英文版(可切换中英文) 很多朋友将MyEclipse汉化后还想改回英文的,其实只要修改MyEclipse的配置文件就可以了,这里我以MyEclipse7.0为例演示一下如何 ...

  5. Java JDBC高级特性

    1.JDBC批处理 实际开发中需要向数据库发送多条SQL语句,这时,如果逐条执行SQL语句,效率会很低,因此可以使用JDBC提供的批处理机制.Statement和PreparedStatemen都实现 ...

  6. [PHP]程序员技能栈

    [PHP]程序员技能栈.md-/Users/zjh/Documents/我的文章/[PHP]程序员技能栈 html{font-family: sans-serif;-ms-text-size-adju ...

  7. Hibernate一对一关联映射配置

    一.一对一关联 Hibernate提供了两种映射一对一关联关系的方式:按照外键映射和按照主键映射.下面以员工账号和员工档案表为例,介绍这两种映射方式,并使用这两种映射方式分别完成以下持久化操作: (1 ...

  8. reflect2015破解

    具体看 http://download.congci.com/download/net-reflector-7-6-1-824-wanquan-pojie#downloads *博主注:因为很多破解程 ...

  9. SQL部分 数据库的建立 增删改查

    数据库: 结构化查询语言(Structured Query Language)简称SQL: 数据库管理系统(Database Management System)简称DBMS: 数据库管理员(Data ...

  10. J2EE中关于tomcat的maxIdle、maxActive、maxActive相关配置

    一.基本概念 1 maxActive 连接池的最大数据库连接数.设为0表示无限制,一般把maxActive设置成可能的并发量就行了 2 maxIdle 最大的空闲连接数 3 maxWait 最大建立连 ...