FileStream.Seek与缓冲读取的区别

6

这个答案的启发,我想知道如果使用大量的FileStream.Seek(-1)会发生什么。

为了清晰起见,我将重新发布答案:

using (var fs = File.OpenRead(filePath))
{
    fs.Seek(0, SeekOrigin.End);

    int newLines = 0;
    while (newLines < 3)
    {
        fs.Seek(-1, SeekOrigin.Current);
        newLines += fs.ReadByte() == 13 ? 1 : 0; // look for \r
        fs.Seek(-1, SeekOrigin.Current);
    }

    byte[] data = new byte[fs.Length - fs.Position];
    fs.Read(data, 0, data.Length);
}

个人建议读取2048字节到缓冲区中,然后在缓冲区中查找该字符。

使用反编译工具Reflector我发现该方法内部使用了SetFilePointer

关于Windows缓存和倒序读取文件的任何文档资料吗?当连续使用Seek(-1)时,Windows是否会倒序缓存并查询缓存,还是会从当前位置向前读取?

值得注意的是,大多数人都认为Windows进行了良好的缓存,但是与此同时,“倒序读取文件”的每个答案都涉及读取字节块并对其进行处理。


1
你在认真地进行同行评审吗? - ChaosPandion
1
@ChaosPandion:我没有评价你的评论,我只是好奇。 - VVS
2个回答

8
前进和后退通常没有太大区别。第一次读取文件数据后,它会被读入文件系统缓存中,使用ReadByte()进行内存到内存的复制。只要数据在缓存中,这个复制就不会受到文件指针值的影响。但是缓存算法假定你通常是顺序读取的。它会尝试向前读取,只要文件扇区仍在同一个磁道上。除非磁盘严重碎片化,否则它们通常都在。

但是,这种方法效率低下。每个字节都需要两个pinvoke和API调用。这其中有相当多的开销,同样的两个调用也可以使用相同的开销读取65千字节。通常情况下,只有在发现性能瓶颈时才进行修复。


啊,没有考虑调用p/invoking的成本。这已经足够的理由来分块读入了。 - VVS

1

这里有一个指向Windows文件缓存的指针。

行为也可能取决于文件所在的物理位置(硬盘、网络等)以及本地配置/优化。

另一个重要的信息来源是CreateFile API文档:CreateFile函数

有一个很好的部分名为“缓存行为”,至少告诉我们如何影响文件缓存,至少在非托管世界中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接