C# Error: OutOfMemoryException - Reading a large text file and replacing from dictionary
C# Error: OutOfMemoryException - Reading a large text file and replacing from dictionary
总的来说,我是 C# 和面向对象编程的新手。我有一个解析文本文件的应用程序。
应用程序的objective是读取提供的文本文件的内容并替换匹配的值。
当提供大约 800 MB 到 1.2GB 的文件作为输入时,应用程序崩溃并出现错误 System.OutofMemoryException。
在研究过程中,我发现了几个建议将 目标平台:更改为 x64 的答案。
更改目标平台后存在同样的问题。
代码如下:
// Reading the text file
var _data = string.Empty;
using (StreamReader sr = new StreamReader(logF))
{
_data = sr.ReadToEnd();
sr.Dispose();
sr.Close();
}
foreach (var replacement in replacements)
{
_data = _data.Replace(replacement.Key, replacement.Value);
}
//Writing The text File
using (StreamWriter sw = new StreamWriter(logF))
{
sw.WriteLine(_data);
sw.Dispose();
sw.Close();
}
错误指向
_data = sr.ReadToEnd();
replacements 是一个字典。 Key包含原始单词,Value包含要替换的单词。
Key 元素替换为 KeyValuePair 的 Value 元素。
正在遵循的方法是读取文件、替换和写入。
我尝试使用 StringBuilder 而不是字符串,但应用程序崩溃了。
这可以通过一次一行地读取文件、替换和写入来克服吗?做同样的事情的有效和更快的方法是什么。
更新:系统内存为 8 GB,在监控性能时,内存使用率飙升至 100%。
@Tim Schmelter 的回答很有效。
但是,内存使用率飙升超过 90%。可能是由于以下代码:
String[] arrayofLine = File.ReadAllLines(logF);
// Generating Replacement Information
Dictionary<int, string> _replacementInfo = new Dictionary<int, string>();
for (int i = 0; i < arrayofLine.Length; i++)
{
foreach (var replacement in replacements.Keys)
{
if (arrayofLine[i].Contains(replacement))
{
arrayofLine[i] = arrayofLine[i].Replace(replacement, masking[replacement]);
if (_replacementInfo.ContainsKey(i + 1))
{
_replacementInfo[i + 1] = _replacementInfo[i + 1] + "|" + replacement;
}
else
{
_replacementInfo.Add(i + 1, replacement);
}
}
}
}
//Creating Replacement Information
StringBuilder sb = new StringBuilder();
foreach (var Replacement in _replacementInfo)
{
foreach (var replacement in Replacement.Value.Split('|'))
{
sb.AppendLine(string.Format("Line {0}: {1} ---> \t\t{2}", Replacement.Key, replacement, masking[replacement]));
}
}
// Writing the replacement information
if (sb.Length!=0)
{
using (StreamWriter swh = new StreamWriter(logF_Rep.txt))
{
swh.WriteLine(sb.ToString());
swh.Dispose();
swh.Close();
}
}
sb.Clear();
它找到进行替换的行号。是否可以使用 Tim 的代码捕获此数据以避免多次将数据加载到内存中。
如果您有非常大的文件,您应该尝试 MemoryMappedFile
,它专为此目的而设计(文件 > 1GB),可以将文件的 "windows" 读入内存。但是使用起来并不方便。
一个简单的优化是逐行读取和替换
int lineNumber = 0;
var _replacementInfo = new Dictionary<int, List<string>>();
using (StreamReader sr = new StreamReader(logF))
{
using (StreamWriter sw = new StreamWriter(logF_Temp))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
lineNumber++;
foreach (var kv in replacements)
{
bool contains = line.Contains(kv.Key);
if (contains)
{
List<string> lineReplaceList;
if (!_replacementInfo.TryGetValue(lineNumber, out lineReplaceList))
lineReplaceList = new List<string>();
lineReplaceList.Add(kv.Key);
_replacementInfo[lineNumber] = lineReplaceList;
line = line.Replace(kv.Key, kv.Value);
}
}
sw.WriteLine(line);
}
}
}
如果你想覆盖旧的,最后你可以使用File.Copy(logF_Temp, logF, true);
。
只要应用程序尝试分配内存以执行操作但失败,就会抛出 OutOfMemoryException。根据 Microsoft 的文档,以下操作可能会引发 OutOfMemoryException:
装箱(即,将值类型包装在对象中)
创建数组
创建对象
如果您尝试创建无限数量的对象,那么可以合理地假设您迟早会 运行 内存不足。
(注意:不要忘记 垃圾收集器。 根据正在创建的对象的生命周期,如果确定它们不存在,它将删除其中的一些使用时间更长。)
我怀疑是这一行:
foreach (var replacement in replacements)
{
_data = _data.Replace(replacement.Key, replacement.Value);
}
你迟早会 运行 内存不足。你数过它循环了多少次吗?
尝试
- 增加可用内存。
- 减少您检索的数据量。
逐行读取文件并将更改的行附加到其他文件。最后用新文件替换源文件(是否创建备份)。
var tmpFile = Path.GetTempFileName();
using (StreamReader sr = new StreamReader(logF))
{
using (StreamWriter sw = new StreamWriter(tmpFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
foreach (var replacement in replacements)
line = line.Replace(replacement.Key, replacement.Value);
sw.WriteLine(line);
}
}
}
File.Replace(tmpFile, logF, null);// you can pass backup file name instead on null if you want a backup of logF file
总的来说,我是 C# 和面向对象编程的新手。我有一个解析文本文件的应用程序。
应用程序的objective是读取提供的文本文件的内容并替换匹配的值。
当提供大约 800 MB 到 1.2GB 的文件作为输入时,应用程序崩溃并出现错误 System.OutofMemoryException。
在研究过程中,我发现了几个建议将 目标平台:更改为 x64 的答案。
更改目标平台后存在同样的问题。
代码如下:
// Reading the text file
var _data = string.Empty;
using (StreamReader sr = new StreamReader(logF))
{
_data = sr.ReadToEnd();
sr.Dispose();
sr.Close();
}
foreach (var replacement in replacements)
{
_data = _data.Replace(replacement.Key, replacement.Value);
}
//Writing The text File
using (StreamWriter sw = new StreamWriter(logF))
{
sw.WriteLine(_data);
sw.Dispose();
sw.Close();
}
错误指向
_data = sr.ReadToEnd();
replacements 是一个字典。 Key包含原始单词,Value包含要替换的单词。
Key 元素替换为 KeyValuePair 的 Value 元素。
正在遵循的方法是读取文件、替换和写入。
我尝试使用 StringBuilder 而不是字符串,但应用程序崩溃了。
这可以通过一次一行地读取文件、替换和写入来克服吗?做同样的事情的有效和更快的方法是什么。
更新:系统内存为 8 GB,在监控性能时,内存使用率飙升至 100%。
@Tim Schmelter 的回答很有效。
但是,内存使用率飙升超过 90%。可能是由于以下代码:
String[] arrayofLine = File.ReadAllLines(logF);
// Generating Replacement Information
Dictionary<int, string> _replacementInfo = new Dictionary<int, string>();
for (int i = 0; i < arrayofLine.Length; i++)
{
foreach (var replacement in replacements.Keys)
{
if (arrayofLine[i].Contains(replacement))
{
arrayofLine[i] = arrayofLine[i].Replace(replacement, masking[replacement]);
if (_replacementInfo.ContainsKey(i + 1))
{
_replacementInfo[i + 1] = _replacementInfo[i + 1] + "|" + replacement;
}
else
{
_replacementInfo.Add(i + 1, replacement);
}
}
}
}
//Creating Replacement Information
StringBuilder sb = new StringBuilder();
foreach (var Replacement in _replacementInfo)
{
foreach (var replacement in Replacement.Value.Split('|'))
{
sb.AppendLine(string.Format("Line {0}: {1} ---> \t\t{2}", Replacement.Key, replacement, masking[replacement]));
}
}
// Writing the replacement information
if (sb.Length!=0)
{
using (StreamWriter swh = new StreamWriter(logF_Rep.txt))
{
swh.WriteLine(sb.ToString());
swh.Dispose();
swh.Close();
}
}
sb.Clear();
它找到进行替换的行号。是否可以使用 Tim 的代码捕获此数据以避免多次将数据加载到内存中。
如果您有非常大的文件,您应该尝试 MemoryMappedFile
,它专为此目的而设计(文件 > 1GB),可以将文件的 "windows" 读入内存。但是使用起来并不方便。
一个简单的优化是逐行读取和替换
int lineNumber = 0;
var _replacementInfo = new Dictionary<int, List<string>>();
using (StreamReader sr = new StreamReader(logF))
{
using (StreamWriter sw = new StreamWriter(logF_Temp))
{
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
lineNumber++;
foreach (var kv in replacements)
{
bool contains = line.Contains(kv.Key);
if (contains)
{
List<string> lineReplaceList;
if (!_replacementInfo.TryGetValue(lineNumber, out lineReplaceList))
lineReplaceList = new List<string>();
lineReplaceList.Add(kv.Key);
_replacementInfo[lineNumber] = lineReplaceList;
line = line.Replace(kv.Key, kv.Value);
}
}
sw.WriteLine(line);
}
}
}
如果你想覆盖旧的,最后你可以使用File.Copy(logF_Temp, logF, true);
。
只要应用程序尝试分配内存以执行操作但失败,就会抛出 OutOfMemoryException。根据 Microsoft 的文档,以下操作可能会引发 OutOfMemoryException:
装箱(即,将值类型包装在对象中) 创建数组 创建对象 如果您尝试创建无限数量的对象,那么可以合理地假设您迟早会 运行 内存不足。
(注意:不要忘记 垃圾收集器。 根据正在创建的对象的生命周期,如果确定它们不存在,它将删除其中的一些使用时间更长。)
我怀疑是这一行:
foreach (var replacement in replacements)
{
_data = _data.Replace(replacement.Key, replacement.Value);
}
你迟早会 运行 内存不足。你数过它循环了多少次吗?
尝试
- 增加可用内存。
- 减少您检索的数据量。
逐行读取文件并将更改的行附加到其他文件。最后用新文件替换源文件(是否创建备份)。
var tmpFile = Path.GetTempFileName();
using (StreamReader sr = new StreamReader(logF))
{
using (StreamWriter sw = new StreamWriter(tmpFile))
{
string line;
while ((line = sr.ReadLine()) != null)
{
foreach (var replacement in replacements)
line = line.Replace(replacement.Key, replacement.Value);
sw.WriteLine(line);
}
}
}
File.Replace(tmpFile, logF, null);// you can pass backup file name instead on null if you want a backup of logF file