文件操作:如何做好普通的C#文件

在开发过程中,我们需要与文件进行很多交互。读文件、写文件已成为家常便饭,本地操作完美。但是,我们一进入生产环境,在开发中往往会有很多意想不到的惊喜或者麻烦。因此,我对常见的C#文件操作做了一个总结,大部分问题如下:

1:将一些内容写入文件,在另一个进程/线程/后续操作中要读取文件内容时报异常,提示System.IO.IOException: The file “XXX” is being used by another process, So该进程无法访问此文件。

2:对一个文件进行了一些操作(读/写),然后尝试追加,仍然报System.IO.IOException: The file “XXX” is being used by another process, so the process cannot access this file. 这个问题与 1 类似。

3:对文件进行一些操作后,如果要删除该文件,仍然报System.IO.IOException: The file “XXX” is being used by another process, so the process cannot access this file。

看到这些,有经验的同学应该会说资源没有放出来,不过也有以下几种可能。我们对文件的操作非常频繁,所以我们编写了特定的操作类/组件来维护文件之间的操作,直到它们在特定的时间结束,例如日志,它随着程序的启动而开始写入,直到程序关闭。. 但是我们还需要提供一个特殊的操作(读/写/删除)来操作文件。例如,我们需要提供一个日志查看器来查看当前日志或所有日志。这时候,上述情况就难免发生了。问题。

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);

一切都很简单,访问方式是只读的,所以应该和上面的写锁没有冲突!

但是结果不是我们预期的c语言通讯录记事本读取,为什么提示无法访问呢?回想我之前用Windows记事本打开文件,并没有提示文件被锁定,确实可以访问,那为什么在程序中访问不了呢?或许,我们应该重点关注FileMode、FileAccess、FileShare这三个枚举,或许它们就是鬼。

更多linux内核视频教程文字资料可后台私信【内核】免费获取。

文件模式

MSDN上的解释是指定操作系统打开文件的方式。我认为这不需要解释。我们通常经常使用它。MSDN的表格也很好的解释了各个枚举值的作用,就不解释了。

文件访问

定义文件读、写或读/写访问的常量。

这个枚举用的也很多,说明也很通俗易懂,就不多解释了。^_^!

文件共享

相信这个枚举类型大家会比较陌生,甚至有的同学从来没有见过(惭愧,我才认识很久),陌生就是陌生,但是它的威力也不容小觑,但是.net帮助我们 封装得非常好,以至于我们一度认为它不是一个重要的角色。好吧,进入主题!

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

看它的成员描述,和 FileAccess 很像c语言通讯录记事本读取,让我们一起来揭开它的一时之谜吧!

文件共享.读取

从字面上看,我们可以理解为,在第一次打开文件后(资源没有被释放),就可以只读方式读取文件,而不会抛出无法访问文件的异常。使用刚刚实现的方法,这个实验又可以轻松完成了:

WriteFile(FileMode.Create, FileAccess.Write, FileShare.Read);
ReadFile(FileAccess.Read, 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 允许您执行后续删除操作。

黑匣子的内容

对于文件操作,我们通常使用以下类型:

File.AppendAllText("......");
File.AppendAllLines(...);
File.AppendText(...);
FileStream fs = new FileStream(path, FileAccess.Write);
fs.Write(....);

事实上,他们也在内部初始化了 FileMode/FileAccess/FileShare。比如 File 的静态方法最终会生成一个

调用私有方法的 Stream 实例

结尾

现在,我们明白了,其实 /FileShare 就是控制文件流的“访问权限”。当然,这只是入门级的文件操作。我自己做了笔记,希望对你有帮助。小前辈写了一篇关于文件读写锁的文章。有兴趣的同学可以搜一下去观看!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论