将 StringBuilder 的 OutOfMemoryException 的长度设置为 0

Putting length to 0 for OutOfMemoryException of StringBuilder

我有一个代码块,它获取一个文件并附加所需数据,如下所示:

var srBuilder = new StringBuilder();
using (var file = new StreamReader(document.FullSourcePath, Encoding.ASCII))
            {
                while (!file.EndOfStream)
                {                 
                    var bytess = new char[numBytes];
                    file.ReadBlock(bytess , 0, bytess.Length);
                    srBuilder.Append(buff);
                }

                document.Document += srBuilder.ToString();  ////Exception occures here
            }

但是当文件超过 200 MB 时,它会抛出 OutofMemoryException。

我想的是将字符串生成器的长度设为零,如下所示:

 while (!file.EndOfStream)
        {  
            srBuilder.Length = 0;      //// Here         
            var bytess = new char[numBytes];
            file.ReadBlock(bytess , 0, bytess.Length);
            srBuilder.Append(buff);
        }

这是最佳解决方案还是需要其他任何解决方案?

我不知道你为什么把它搞得那么复杂。您只需要一行:

document.Document += File.ReadAllText(document.FullSourcePath, Encoding.ASCII);

如果这抛出异常,那么是的,可能是您没有足够的内存。

您的最终目标是将一个 200 MB 的 ASCII 文件分配给 document.Document 成员变量,我假设它是字符串类型。

长话短说:你不能这样做,需要重新考虑你的方法。

无论如何,你的这个要求将需要 400 MB 的连续内存(给定的字符串是 char[] 个 UTF-16 字符数组,每个字符占 2 个字节),这几乎不可能获得在 32 位进程中,运行 时间抛出的 OutOfMemoryException 试图告诉您。

您将要找到的任何 "trick" 都会有其缺点。

  • 分块读取文件无关紧要,因为最终结果是一样的:最终的字符串仍然需要 400 MB 的连续内存。
  • 通过谷歌搜索 "C# StringBuilder OutOfMemoryException" 将 StringBuilderLength 设置为 0,将使异常消失,但只会导致文件的最后一个块被分配至 document.Document。可以肯定地说你也不想那样。
  • 仅在 64 位机器上将项目更改为 运行 可能 是一个选项,但很可能不会(硬件和其他依赖项),并且是一个隐藏实际问题的肮脏解决方法,就像在被吹断的腿上贴创可贴:您忽略了致命的设计错误。有一天,有人要为您的应用程序提供一个 2 GB 的文件,而您又回到了原点。

您需要文件,并逐行处理它。

foreach (string line in File.ReadLines(filename))
{
    // process line
}