假设我有一个编辑文本文件的C#应用程序。每个文件使用的技术可以是以下两种之一:
1) 一次性将文件读入字符串,进行更改,并将该字符串写入现有文件:
string fileContents = File.ReadAllText(fileName);
// make changes to fileContents here...
using (StreamWriter writer = new StreamWriter(fileName))
{
writer.Write(fileContents);
}
2) 逐行读取文件,将更改写入临时文件,然后删除源文件并重命名临时文件:
using (StreamReader reader = new StreamReader(fileName))
{
string line;
using (StreamWriter writer = new StreamWriter(fileName + ".tmp"))
{
while (!reader.EndOfStream)
{
line = reader.ReadLine();
// make changes to line here
writer.WriteLine(line);
}
}
}
File.Delete(fileName);
File.Move(fileName + ".tmp", fileName);
这些选项的性能考虑是什么?
在我看来,无论是按行读取还是一次性读取整个文件,读取的数据量都是相同的,磁盘时间将占主导地位而内存分配时间则不占优势。话虽如此,一旦文件被加载到内存中,操作系统就可以自由地将其分页,当这样做时,大读取的好处已经丧失了。另一方面,在使用临时文件时,一旦句柄关闭,我需要删除旧文件并重命名临时文件,这会产生一定的开销。
然后有关缓存、预读和磁盘缓冲区大小等问题......
我假设在某些情况下,一次性读取文件更好,而在其他情况下,按行操作更好。我的问题是,这两种情况的条件是什么?
ReadAllBytes
这样的方法不包括指定长度的选项,以及一个选项参数来指示如何处理比该长度长或短的文件(如果较短:填充、返回实际大小或抛出异常;如果较长,则返回前导部分或抛出异常)?在许多情况下,应用程序会有一些最大合理大小的概念,尝试读取超过此大小的内容最好干净地抛出异常,而不是导致可能破坏其他无关线程的内存不足错误。 - supercatOpenRead
的结构存在,它返回一个流,你可以很容易地控制每次读取多少数据到缓冲区。ReadAllBytes
更像是边缘情况,它只是作为一个帮助程序存在。 - Rex MReadAllBytes
展示了与gets()
相同的懒惰,并且只是稍微不那么邪恶(内存不足错误不像随机内存覆盖那样糟糕,但仍然会导致崩溃)。 - supercat