代码之家  ›  专栏  ›  技术社区  ›  Remy

执行清除文本文件中过多旧数据的方法

  •  1
  • Remy  · 技术社区  · 7 年前

    我有一些文本文件,我需要能够在飞行中写,而且经常。这些文件的大小可能会非常大,但在两次迭代之间,它们内部的文本可能会完全不同。

    这意味着文本可以比以前短。如果我不先清除旧数据,最终会在新数据的末尾附加旧数据。如msdn文件所示。

    如果用较短的字符串(如“second run”)覆盖较长的字符串(如“this is a test of the openwrite method”),则该文件将包含字符串组合(“second run test of the openwrite method”)。

    但是,文档没有指定一种补救方法,甚至没有阻止这种情况的发生。

    目前我正在做以下工作:

    File.WriteAllText(path, string.Empty);
    using (Stream file = File.OpenWrite(path))
    {
        file.Write(dataToWrite, 0, dataToWrite.Length);
    }
    

    在这里,我清空现有文件的内容,使用 File.WriteAllText(path, string.Empty) 然后将新内容写入文件。

    但是,如果必须对整个文件进行两次检查(首先清除文件,然后将新数据写入其中),则感觉这是一种浪费。

    有没有一种方法可以用我的新数据覆盖旧数据,并且只遍历“剩余”数据并清除它,而不遍历整个文件两次?

    不一定要用 Stream.Write . 任何能够更快完成任务的替代方案都是可以接受的。


    结果

    在不同的机器上运行10万次写入2441kb数据(并清除所有旧数据)的迭代5次后,得出以下结果:

    • 我在上面找到的原始方法 4.75589 ms 平均而言。
    • 安德森·皮门特尔的 answer 使用 WriteAllBytes 4.28946 ms 平均而言。
    • 最快的 黑暗猎鹰 answer 使用 file.Write 截取 4.14433 ms 平均而言(并且是最快/最符合这一点的)。
    • File.Delete 旧文件并使用 FileStream.Write 5.31883 ms 平均而言。
    • MeJustAndrew answer 做上面的但是多线程 8.12726 ms 平均而言。(尽管我不得不承认,这很可能是因为我的实现不好,但我在多线程方面没有任何经验)

    请注意,这些结果适用于 我的 implementation 和硬件。结果可能因硬件而异。

    3 回复  |  直到 7 年前
        1
  •  2
  •   Dark Falcon    7 年前

    我建议截断文件:

    using (FileStream file = File.OpenWrite(path))
    {
        file.Write(dataToWrite, 0, dataToWrite.Length);
        file.SetLength(dataToWrite.Length);
    }
    

    您应该测试这是否比写入新文件、删除旧文件以及将新文件重命名为旧名称更好。

        2
  •  1
  •   Anderson Pimentel    7 年前

    你只需写:

    File.WriteAllBytes(path, dataToWrite);
    

    根据 MSDN :

    创建新文件,将指定的字节数组写入该文件,然后 然后关闭文件。如果目标文件已存在,则为 改写。

        3
  •  1
  •   meJustAndrew    7 年前

    正如我提到的,多线程方法如下所示:

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

    注意:我不能保证这段代码的正确行为,因为我没有测试过它。