我将数据存储在几个单独的文本文件中,然后我会解析和分析。
处理的数据大小差异很大。它的范围从几百兆字节(或更少)到10千兆字节。
我开始将解析后的数据存储在List<DataItem>
中,因为我想在分析过程中执行BinarySearch()
。但是,如果解析了太多数据,程序将抛出OutOfMemory-Exception。解析器可以处理的确切数量取决于内存的碎片。有时它只有1.5 GB的文件,有些时候它只有3 GB。
目前我使用的List<List<DataItem>>
条目数量有限,因为我认为它会改变任何东西。但是没有任何重大改进。
我尝试的另一种方法是序列化解析器数据,然后根据需要对其进行反序列化。这种方法的结果更糟。整个过程耗时更长。
我查看了内存映射文件,但我真的不知道它们是否可以帮助我,因为我之前从未使用它们。他们会吗?
那么如何快速访问所有文件中的数据,而不会有OutOfMemoryException
并根据其属性查找DataItem
的危险?
void Parse() {
LoadFile();
for (int currentLine = 1; currentLine < MAX_NUMBER_OF_LINES; ++currentLine) {
string line = GetLineOfFile(currentLine);
string[] tokens = SplitLineIntoTokens(line);
DataItem data = PutTokensIntoDataItem(tokens);
try {
List<DataItem>.Add(data);
} catch (OutOfMemoryException ex) {}
}
}
void LoadFile(){
DirectoryInfo di = new DirectroyInfo(Path);
FileInfo[] fileList = di.GetFiles();
foreach(FileInfo fi in fileList)
{
//...
StreamReader file = new SreamReader(fi.FullName);
//...
while(!file.EndOfStram)
strHelp = file.ReadLine();
//...
}
}
答案 0 :(得分:1)
如果您问题中的代码代表实际代码,则看起来您正在将所有文件中的所有数据读入内存,然后进行解析。也就是说,你有:
Parse()
LoadFile();
for each line
....
您的LoadFile
将所有文件加载到内存中。或者看起来如此。这非常浪费,因为除了解析时创建的对象外,还保留了所有未解析行的列表。
您可以改为一次只加载一行,解析它,然后丢弃未解析的行。例如:
void Parse()
{
foreach (var line in GetFileLines())
{
}
}
IEnumerable<string> GetFileLines()
{
foreach (var fileName in Directory.EnumerateFiles(Path))
{
foreach (var line in File.ReadLines(fileName)
{
yield return line;
}
}
}
这限制了用于保存文件名的内存量,更重要的是,限制了未解析行占用的内存量。
此外,如果您对最终数据中的行数有上限,则可以预先分配列表,以便添加到列表中不会导致重新分配。因此,如果您知道您的文件将包含不超过1亿行,您可以写:
void Parse()
{
var dataItems = new List<DataItem>(100000000);
foreach (var line in GetFileLines())
{
data = tokenize_and_build(line);
dataItems.Add(data);
}
}
这可以减少碎片和内存不足错误,因为列表已预先分配以保存您期望的最大行数。如果预分配有效,那么您就知道自己有足够的内存来保存对正在构建的数据项的引用。
如果内存不足,则必须查看数据项的结构。也许您在其中存储了太多信息,或者有办法减少用于存储这些项目的内存量。但是,如果您需要帮助减少其占用空间,则需要向我们提供有关数据结构的更多信息。
答案 1 :(得分:0)
您可以使用:
我认为它会减少内存异常并使文件处理更快。