清除文本文件中过多旧数据的高性能方法

时间:2019-01-31 12:53:27

标签: c# performance file

我需要一些文本文件,并且需要经常写这些文件。这些文件的大小可能会很大,但两次迭代之间的文本可能会完全不同。

这意味着文本可以比以前短。如果我不先清除旧数据,最终将混合新数据并附加到新数据的末尾。如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
  • 安德森·皮门特尔(Anderson Pimentel)使用WriteAllBytes的{​​{3}}平均花费了4.28946 ms
  • 最快黑暗猎鹰的answer使用file.Write并进行截断平均花费了4.14433 ms(并且与此最快/最一致)。
  • File.Delete旧文件并使用FileStream.Write创建新文件平均花费5.31883 ms
  • MeJustAndrew的answer进行了上述操作,但多线程平均花费了8.12726 ms。 (尽管我不得不承认这很可能是由于我的执行不力,但我对多线程的经验丝毫没有。)

请注意,这些结果适用于 my answer和硬件。在不同的硬件上,结果可能会有所不同。

3 个答案:

答案 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);
    }
}

注意:由于我尚未测试此代码,因此我不保证此代码的正确行为。