我这几天一直在寻找解决我遇到的一些关键问题的方法,但我还没有找到这个问题的好的答案。
我正在开展一个学术(/学习)项目,该项目涉及定期读取 3-50MB 的纯文本文件,并最终读取数百万条记录(我当前的数据集约为 800,000 条记录)
假设文件不能被split()
分成 block ,那么在函数之间传递这个 block 的最佳方法是什么?按值传递让我想到(并且我相信,看到)将 50MB 文件传递给函数,并返回 20-30MB 结果集,意味着我已经浪费了超过 100MB 的内存,只是传递正在等待的文件在 GC 处回收。 (从技术上讲,文件可以被 split() ,但这些 split() 有时每个都 10MB 大,并且每个在处理时都必须保留)
我最近对整个项目进行了重大更改,这次我想更好设计处理部分。以前的方法主要读取并处理驱动程序本身中的数据——没有数据容器。当我尝试使用数据容器时,我最终得到了类似的结果。这是我使用的第一种方法:
- 将整个 3-50 MB+ 文件读取到字符串
- 正则表达式/拆分为 4-15 个 block (由文件中类似 XML 的标记确定)
- 将 1-3 个 block 传递给函数 A(查找某些数据)
- 再将 4-5 个 block 传递给函数 B(寻找不同的数据,这些数据不会存在于函数 A block 中)
- 在驱动程序函数中收集结果
- 将结果集拼接在一起,并写入磁盘(我现在知道我应该创建并附加)
我可能可以在阅读时进行拆分,但是,即使这些拆分的大小每个(或更多)也可以是 5MB,并且我需要将其中大部分保留在内存中,直到文件处理完成(如果步骤 3 发生变化)步骤 4 是如何工作的).. 更糟糕的是,一些输入 readLine() 本身可能有 1-2MB 长(在 \n
之前)。
那么,什么样的设计策略最适合处理这些巨大的输入文件和巨大的字符串?
最佳答案
Pass-by-value leads me to think (and, I believe, see) passing a 50MB file to a function, and returning a 20-30MB result set, means I have used wasted over 100MB memory just passing the file that's waiting to be reclaimed at GC.
不正确。 Java 按值传递引用,而不是整个String
。我要做的就是传递(引用)字符串以及要处理的字符串部分的开始和结束索引。
void read()
{
String input = /*your code here*/;
process(input, 37, 17576);
}
process(String input, int startIndex, int endIndex)
{
/*your code here, e.g.
for(int i = startIndex; i < endIndex; i++)
{
//do stuff
}*/
}
此外,如果 read
和 process
位于同一个类中,则可以将字符串设为类字段:
String input;
void read()
{
input = /*your code here*/;
process(37, 17576);
}
process(int startIndex, int endIndex)
{
/*your code here, e.g.
for(int i = startIndex; i < endIndex; i++)
{
//do stuff
}*/
}
关于java - 正确处理巨大的输入和处理字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22305493/