【问题标题】:What is the BEST way to replace text in a File using C# / .NET?使用 C#/.NET 替换文件中文本的最佳方法是什么?
【发布时间】:2010-10-25 22:13:03
【问题描述】:

我有一个文本文件,它作为一个非常大的数据提取的一部分被写入。文本文件的第一行是提取的“帐户”数量。

由于此提取的性质,该数字直到过程结束时才知道,但文件可能很大(几百兆)。

在 C#/.NET 中打开文件(在本例中为简单文本文件)并替换文本第一“行”中的数据的最佳方式是什么?

重要提示: - 我不需要替换“固定数量的字节” - 这很容易。这里的问题是需要在文件顶部插入的数据是可变的。

重要说明 2:- 一些人曾询问/提到只是将数据保存在内存中然后替换它......但这完全不可能。之所以要更新此进程,是因为它有时会在将一些演出加载到内存时崩溃。

【问题讨论】:

  • "#####\r\n(表示没有填充)" 你确定不能有前导零吗?

标签: c# .net file-io replace


【解决方案1】:

如果提取的文件只有几百兆字节,那么您可以轻松地将所有文本保留在内存中,直到提取完成。然后,您可以将输出文件作为最后一个操作,从记录数开始。

【讨论】:

  • 我的机器上只有 2 个 Gig——我们办公室的其他大多数人都有 4 到 8 个。200MB 是多少。可能占总内存的 10%...
  • 那么在文件“只有几 GB”的几年后会发生什么,那么你还要把它全部保存在内存中吗?
  • 我现在应该花时间担心两年后会发生什么吗?几年后,我希望能够运行至少 8GB RAM 的 quadproc x64 机器。为什么我不能记住它?
  • 把时间花在不必要的优化上是浪费时间。现在做简单的事情,然后如果“两年后”情况发生变化,请升级计算机的内存。你最近看到内存的代价了吗?他们免费赠送(嗯,几乎)。
  • 物理内存量无关。对于非常大的分配而言,重要的是进程地址空间的大小。在 32 位进程中,默认情况下为 2 GB。所以一个 200 MB 的文件是整个地址空间的 10%。这是一个非常大的分配量,无需认真考虑。在 CLR 中它将来自未压缩的大对象堆,这意味着碎片。如果您编写一个 64 位程序,那就是另一回事了,但您可能会发现由于指针大小加倍,性能会在其他方面受到影响。
【解决方案2】:

如果可以的话,您应该插入一个占位符,并在末尾用实际数字和空格覆盖。

如果这不是一个选项,请先将您的数据写入缓存文件。当您知道实际数字时,创建输出文件并从缓存中追加数据。

【讨论】:

  • 这是我喜欢要做的(保留一些空白)-唯一的问题是我要写入的文件格式需要精确的### ##\r\n (表示没有填充)。 - 不过答案很好。
  • @Henk - 前导零上没有 - 如果可以接受,“Binary Worrier”提出了一个很好的解决方案。
【解决方案3】:

我不需要替换“固定 字节数”

你确定吗? 如果您在文件的第一行写入一个大数字(UInt32.MaxValue 或 UInt64.MaxValue),那么当您找到正确的实际数字时,您可以用正确的数字替换该字节数,但用零填充,所以它仍然是一个有效的整数。 例如

Replace  999999 - your "large number placeholder"
With     000100 - the actual number of accounts

【讨论】:

  • 聪明的解决方法! - 但是我正在使用的文件规范不会接受...虽然很好的想法:)
  • 这是一个文件规范,它没有回答我的问题:P
  • “这是一个文件规范”并没有告诉我任何事情。您能否包含定义该计数应该是多少的规范的 sn-p ?很抱歉,但我很难想象不能使用前导零的东西。没关系,纯粹是为了我自己的熏陶。谢谢老兄。
【解决方案4】:

BEST 是非常主观的。对于任何较小的文件,您可以轻松地在内存中打开整个文件并使用字符串替换替换您想要的内容,然后重新写入文件。

即使对于较大的文件,加载到内存中也不会那么难。在多千兆内存的时代,我认为数百兆字节仍然可以轻松地在内存中完成。

您是否测试过这种幼稚的方法?你看到过真正的问题吗?

如果这是一个非常大的文件(大小为千兆字节),我会考虑先将所有数据写入临时文件,然后写入正确的文件,先写入标题行,然后附加其余数据.由于它只是文本,我可能会直接使用 DOS:

 TYPE temp.txt >> outfile.txt

【讨论】:

    【解决方案5】:

    在我看来,如果我正确理解了这个问题?

    在 C#/.NET 中打开文件(在本例中为简单文本文件)并替换文本第一“行”中的数据的最佳方式是什么?

    第一次创建令牌 {UserCount} 时,如何在文件顶部放置它。

    然后使用 TextReader 逐行读取文件。如果它是第一行查找 {UserCount} 并替换为您的值。用 TextWriter 写出你读到的每一行

    例子:

        int lineNumber = 1;
        int userCount = 1234;
        string line = null;
    
        using(TextReader tr = File.OpenText("OriginalFile"))
        using(TextWriter tw = File.CreateText("ResultFile"))
        {
    
            while((line = tr.ReadLine()) != null)
            {
                if(lineNumber == 1)
                {
                    line = line.Replace("{UserCount}", userCount.ToString());
                }
    
                tw.WriteLine(line);
                lineNumber++;
            }
    
        }
    

    【讨论】:

    • 这基本上是我必须做的,但我的目标是不必必须创建 2 个文件。
    • 我看到了另一种解决方案,但尚未验证或尝试过。基本上你所做的是使用 StreamWriter 流之类的东西来编写你的第一个文件并保持打开状态。还要按照我建议的占位符写,并保留令牌的起点和终点。所以现在你在文件的末尾并且你有 UserCount 并且只需要返回并用你的值替换令牌。为此,您使用 BitStream,我相信您可以通过访问 StreamWriter.BaseStream 来访问它,并且可以将字节写入流中的特定位置。将尝试测试并发布。
    【解决方案6】:

    好的,我之前提出了一种处理现有文件会更好的方法。

    但是,在您想要创建文件的情况下,在创建过程中返回顶部并写出用户数。这将做到这一点。

    这是一种避免您编写临时文件的方法。

        private void WriteUsers()
        {   
            string userCountString = null;
            ASCIIEncoding enc = new ASCIIEncoding();
            byte[] userCountBytes = null;
            int userCounter = 0;
    
            using(StreamWriter sw = File.CreateText("myfile.txt"))
            {
                // Write a blank line and return
                // Note this line will later contain our user count.
                sw.WriteLine();
    
                // Write out the records and keep track of the count 
                for(int i = 1; i < 100; i++)
                {
                    sw.WriteLine("User" + i);
                    userCounter++;
                }
    
                // Get the base stream and set the position to 0
                sw.BaseStream.Position = 0;
    
                userCountString = "User Count: " + userCounter;
    
                userCountBytes = enc.GetBytes(userCountString);
    
                sw.BaseStream.Write(userCountBytes, 0, userCountBytes.Length);
            }
    
        }
    

    【讨论】:

    • 实际上这是回答编辑现有文件请求的唯一答案...谢谢!
    猜你喜欢
    • 2010-11-06
    • 1970-01-01
    • 2010-09-11
    • 2019-06-23
    • 1970-01-01
    • 2010-09-18
    • 2011-02-19
    • 1970-01-01
    • 2019-09-18
    相关资源
    最近更新 更多