我需要一些文本文件,并且需要经常写这些文件。这些文件的大小可能会很大,但两次迭代之间的文本可能会完全不同。
这意味着文本可以比以前短。如果我不先清除旧数据,最终将混合新数据并附加到新数据的末尾。如MSDN文档所示。
如果您用较短的字符串(例如“ Second run”)覆盖较长的字符串(例如“ This is a test of OpenWrite method”),则文件将包含字符串的混合(“ Second runtest of OpenWrite方法”)。
但是,文档没有指定补救方法,甚至没有阻止这种情况的发生。
当前我正在执行以下操作:
File.WriteAllText(path, string.Empty);
using (Stream file = File.OpenWrite(path))
{
file.Write(dataToWrite, 0, dataToWrite.Length);
}
在这里我使用File.WriteAllText(path, string.Empty)
清空现有文件的内容,然后将新内容写入文件。
但是,必须遍历整个文件两次(首先将其清除,然后将新数据写入其中),这感觉很浪费。
有没有一种方法可以用新数据覆盖旧数据,并且仅遍历“剩余”数据并清除该数据,而无需遍历整个文件两次?
不一定必须使用Stream.Write
。任何可以使工作完成并更快的选择都是可以接受的。
结果
在不同的计算机上运行100.000次迭代以写入2441 kb的数据(并清除所有旧数据)5次后,得出以下结果:
4.75589 ms
。WriteAllBytes
的{{3}}平均花费了4.28946 ms
。file.Write
并进行截断平均花费了4.14433 ms
(并且与此最快/最一致)。File.Delete
旧文件并使用FileStream.Write
创建新文件平均花费5.31883 ms
。8.12726 ms
。 (尽管我不得不承认这很可能是由于我的执行不力,但我对多线程的经验丝毫没有。)请注意,这些结果适用于 my answer和硬件。在不同的硬件上,结果可能会有所不同。
答案 0 :(得分:2)
我建议截断文件:
using (FileStream file = File.OpenWrite(path))
{
file.Write(dataToWrite, 0, dataToWrite.Length);
file.SetLength(dataToWrite.Length);
}
您应该测试此方法是否比写入新文件,删除旧文件并将新文件重命名为旧名称更好。
答案 1 :(得分:1)
您可以写:
File.WriteAllBytes(path, dataToWrite);
根据MSDN:
创建一个新文件,将指定的字节数组写入该文件,然后 然后关闭文件。如果目标文件已经存在,则为 覆盖。
答案 2 :(得分:1)
正如我提到的,多线程方法如下所示:
class FileWriter
{
private int index;
private string fileName = "file.txt";
private readonly object obj = new object();
private string FileName { get { lock (obj) { return fileName + index; } } }
public void Write(string content)
{
lock (obj)
{
int deleteIndex = index;
new Thread(() => DeleteOldFile(deleteIndex)).Start();
index++;
new Thread(() => File.WriteAllText(fileName + index, content)).Start();
}
}
public string GetFileContent()
{
lock (obj)
{
return File.ReadAllText(FileName);
}
}
private void DeleteOldFile(int fileNumber)
{
var fileToBeDeleted = fileName + fileNumber;
if (File.Exists(fileToBeDeleted))
File.Delete(fileToBeDeleted);
}
}
注意:由于我尚未测试此代码,因此我不保证此代码的正确行为。