本文说的随机文件读写的随机的反义词是顺序,这里的随机文件读写对应顺序文件读写。表示文件可以不按照顺序进行读写

进行文件读写的时候,基本上读是几乎不存在问题的,而写的话就稍微坑了一点,在 dotnet 里面默认没有提供 RandomAccessStream 类,这个 RandomAccessStream 类仅在 UWP 中可以使用

如果在不引用 UWP 的 WPF 里面,或者在 ASP.NET Core 以及 Xamarin 里面,也可以通过 FileStream 的 Seek 方法做到进行随机的读写

在随机读写文件的时候使用 FileStream 的 Seek 方法设置当前的文件 Stream 所在的点,此时就可以从 Stream 的这个点开始进行读写。在 Stream 的 Seek 方法会在 FileStream.Windows.cs 调用 SeekCore 方法,在 SeekCore 会调用 Kernel32.SetFilePointerEx 的方法设置到文件的读写

此时使用 Position 属性也能完成,在 FileStream.cs 里面可以看到 Position 的 Set 方法本质也是调用 Seek 方法

        public override long Position
        {
            get {/*忽略代码*/}
        
            set
            {
            	// 忽略代码
                Seek(value, SeekOrigin.Begin);
            }
        }

比较推荐使用 Seek 的方法,因此这个方法功能比较强大,可以设置相对或者从前开始等

大概的做法是如移动到某个字节处开始读写,可以使用如下代码

        private async Task WriteFile(long fileStartPoint, byte[] data, int dataLength)
        {
            Stream.Seek(fileStartPoint, SeekOrigin.Begin);

            await Stream.WriteAsync(data, offset: 0, dataLength);
        }

注意这里的 WriteAsync 使用的第二个参数 offset 指的是第一个参数 byte[] 的偏移而不是写入到 Stream 的偏移。通过 Seek 的方法就能做到让文件支持进行随机读写

另外,如果想要比较大的提升随机文件读写性能,我推荐在知道文件长度的时候通过 SetLength 方法设置文件长度,这样能减少文件碎片分配

如果需要进行多线程读写,此时读可以采用创建多个 FileStream 的方法,注意设置读共享。但如果存在多线程写入,我推荐是使用一个 FileStream 然后其他多个线程委托到一个线程里面进行写入,而不是多个线程同时写入。原因是多个线程同时写入的时候冲突不好处理,加上文件写入有磁盘延迟,此时的写入特别是有长度变化的时候会写出空值

我通过 AsyncQueue 做到多个线程不断写入队列,而一个线程不断从队列取出待写入的数据,写入到文件。这样做的优势在于能做到在一个线程里面写入文件,而其他线程只是委托这个写入文件线程写入,其他线程不访问文件

这部分多线程进行文件随机写入代码放在 github 欢迎小伙伴访问,代码放在 RandomFileWriter.cs 文件

更多 dotnet 底层源代码请看 官方开源代码 本文用到的代码放在 \src\libraries\System.Private.CoreLib\src\System\IO\FileStream.cs\src\libraries\System.Private.CoreLib\src\System\IO\FileStream.Windows.cs 文件

那么文件随机读写的应用是什么?

可以用在一些业务上,这些业务不需要按照顺序读写文件。例如文件的配置的读写等

文件随机读写可以用在文件配置读写上面,例如我知道文件的数据结构,我的某个数据放在第100个字节到第200个字节间,此时我需要读取修改这个数据的内容,我不需要完全去读取前100个字节的内容,我可以直接使用随机读写的方法读取第100个字节到第200个字节的内容。而写入也同理,我不需要从第0个字节开始写入,我可以从第100个字节开始写入。这样能提升一些读写性能


本文会经常更新,请阅读原文: https://blog.lindexi.com/post/C-dotnet-%E4%BD%BF%E7%94%A8-FileStream-%E9%9A%8F%E6%9C%BA%E6%96%87%E4%BB%B6%E8%AF%BB%E5%86%99.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

如果你想持续阅读我的最新博客,请点击 RSS 订阅,推荐使用RSS Stalker订阅博客,或者前往 CSDN 关注我的主页

知识共享许可协议 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系

以下是广告时间

推荐关注 Edi.Wang 的公众号