我有一个代码,可以从大约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允许申请,字符串的长度,列表中的项目数?等?
答案 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 text
。 string
是不可变的。这意味着当您在创建后更改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并不是最好的。