• .NET 6学习笔记(1)——通过FileStream实现不同进程对单一文件的同时读写


    会写这篇纯属机缘巧合,虽然一直以来认为对单一文件的读、写操作是不冲突,可并行的,但实际并未实践过。正好有个UWP的程序要并行读取由Desktop Extension创建的文本,需要有个原型程序来验证,那不妨点开最新的VS 2022,顺手试试新的语法糖。
    首先我们明确本篇对文件的操作均通过FileStream类来实现,FileStream在.NET 6进行了完全的重写,提高了性能和可靠性。但是本篇提到的共享读写权限,在之前版本也是完全支持的。
    本篇提到的同时读写功能依赖FileStream的这个构造函数:

    public FileStream (string path, System.IO.FileMode mode, System.IO.FileAccess access, System.IO.FileShare share);

    接下来我们通过实际的代码来进行分析。创建第一个工程CreateWriteSharedFile,该工程为.NET 6的Console程序,用于新建和写入内容到名为TestFile.txt的文件中。

    var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.txt");
    var fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
    StreamWriter sw = new StreamWriter(fileStream);
    int cout = 0;
    while (true)
    {
        for (var i = 0; i < 10; i++)
        {
            sw.WriteLine(cout++);
            Console.WriteLine(cout);
        }
        sw.Flush();
        await Task.Delay(1000);
    }

    没有命名空间,没有类名和Main函数,这是C# 10里的新语法糖——顶级语句。作为简化后的程序入口点,十分适合简短的示例程序,对初学者也更友好。

    代码的内容也很好懂,就是每隔1秒连续写入10个自增的数字。唯一值得留意的是FileShare.ReadWrite,这个枚举标识对应的是后续其他对该文件的请求,不管是该进程内还是另外进程,均给与ReadWrite的权限。

    我们的第二个工程ReadSharedFile仅做读取的操作,所以上面CreateWriteSharedFile中的FileShare只给Read也可以。但是相反,ReadSharedFile因为要允许CreateWriteSharedFile来进行写操作,所以它必须给与FileShare.Write枚举。

    var path =Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.txt");
    var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read,FileShare.Write);
    var reader = new StreamReader(fileStream);
    
    while (!reader.EndOfStream)
    {
        Console.WriteLine(reader.ReadLine());
        await Task.Delay(1000);
    }

    上述代码是在ReadSharedFile工程中读取由CreateWirteSharedFile创建的TestFile.txt中的内容。想要测试的话,build成功后运行对应的exe文件即可。并行的读和写操作较为容易理解,也不会存在冲突或生成脏数据的问题。

    但如果是同时进行写操作会怎么样呢?之前的FileShare.ReadWrite就是为接下来的测试准备的。我们创建第二个写文件的工程SecondWriteSharedFile,同样要注意除了设置Read以外,还要为CreateWriteSharedFile特别准备Write权限,才能实现两边同时写入该文件的要求。

    var path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "TestFile.txt");
    var fileStream = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
    StreamWriter sw = new StreamWriter(fileStream);
    
    while (true)
    {
        for (var i = 0; i < 10; i++)
        {
            sw.WriteLine("A".PadRight(i,'A'));
            Console.WriteLine("A".PadRight(i, 'A'));
        }
    
        sw.Flush();
        await Task.Delay(1000);
    }

    非常不幸的是,SecondWriteSharedFile在默认情况下,同样会从文件的头部开始写入,这样就覆盖了先运行的CreateWriteSharedFile在同样位置写入的内容。所以在一般情况下,我们要避免并行的写操作,这样极容易互相覆盖产生脏数据。
    本篇简单地讨论了通过FileShare枚举,使用FileStream并行地读写文件的一般场景。希望能够抛砖引玉,给各位大佬在实际生产场景中以微小的帮助。
    示例代码:(因为GitHub经常打不开,我在gitee也同样放了一份)

    https://github.com/manupstairs/FileReadWriteSample
    https://gitee.com/manupstairs/FileReadWriteSample

    以下链接,是MS Learn上Windows开发的入门课程,单个课程三十分钟到60分钟不等,想要补充基础知识的同学点这里:

    开始使用 Visual Studio 开发 Windows 10 应用

    开发 Windows 10 应用程序

    编写首个 Windows 10 应用

    创建 Windows 10 应用的用户界面 (UI)

    增强 Windows 10 应用的用户界面

    在 Windows 10 应用中实现数据绑定

  • 相关阅读:
    Jupyter notebook 读取文件的问题
    机器学习-数据清洗和特征选择
    机器学习-逻辑回归
    Java教程
    13.并发编程
    redis 实现
    CyclicBarrier介绍
    Future模式衍生出来的更高级的应用
    并发编程 futuretask
    整理POST请求方式
  • 原文地址:https://www.cnblogs.com/manupstairs/p/15936993.html
Copyright © 2020-2023  润新知