从多个文件中读取会导致OutOfMemory异常

时间:2017-01-20 15:26:01

标签: c# file text out-of-memory

我有一个代码,可以从大约80MB大小的10个文件中读取文本。但是,我无法成功完成此操作(取决于我尝试的方式),它在第3到第7次迭代时失败了。注释掉的行是我尝试阅读它的方式,每个都失败了。

var lines = new List<string>();
var text = string.Empty;
for (int i = 0; i < 10; i++)
{
    try
    {
        //lines.AddRange(File.ReadAllLines(dirPath + string.Format(@"commands{0}.txt", i)));
        //lines.Add(File.ReadAllText(dirPath + string.Format(@"commands{0}.txt", i)));
        //lines.Add(text);

        var bytes = File.ReadAllBytes(dirPath + string.Format(@"commands{0}.txt", i));
        text += Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes);
    }
    catch (Exception e)
    {
        //OutOfMemory exception
    }
}

我做错了什么?到底有什么限制? MB允许申请,字符串的长度,列表中的项目数?等?

2 个答案:

答案 0 :(得分:1)

text是一个string对象,它有一个限制。 What is the maximum possible length of a .NET string?

你可以使用StringBuilder,它可以通过附加增长超出它的限制。 https://msdn.microsoft.com/en-us/library/system.text.stringbuilder.maxcapacity(v=vs.110).aspx

首先添加using System.Text

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
    var bytes = File.ReadAllBytes(dirPath + string.Format(@"commands{0}.txt", i));
    sb.Append(Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes));
}

答案 1 :(得分:1)

问题出在string textstring是不可变的。这意味着当您在创建后更改string时,将创建新的string对象。

这样做:

text += Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes);

您在每次迭代中创建对象(甚至多个对象 - Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes);创建一个对象,然后您text +=再创建一个对象)。

假设您已阅读第一个文件,然后通过第二个文本附加此string - 将存储包含文件的旧string和包含两个文件中的文本的新string在记忆中。存储旧string但不需要。

有很多内存不需要,但垃圾收集还没有完成(这就是为什么有时你会在第3次迭代中获得异常,有时在第7次 - 如果发生GC,你会更进一步)。

为避免这种情况,请考虑使用byte数组或StringBuilder代替string

关于List<string>

内部列表包含一个数组,当没有用于分配此数组的连续(连续)内存区域时,您也将获得OutOfMemoryException

您可以尝试使用LinkedList<string>

使用StringBuilder

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10; i++)
{
    try
    {
        var bytes = File.ReadAllBytes(dirPath + string.Format(@"commands{0}.txt", i));

        sb.Append(Environment.NewLine);
        sb.Append(System.Text.Encoding.UTF8.GetString(bytes));    

        //avoid sb.Append(Environment.NewLine + System.Text.Encoding.UTF8.GetString(bytes)) 
        //because you still create unnecessary object doing concatenation (+)    
    }
    catch (Exception e)
    {
        //OutOfMemory exception
    }
}

//you can cast "sb" to "string"
string res = sb.ToString();

但你应该考虑创建另一个解决方案。内存容量为800MB并不是最好的。