我正在进行文件处理练习,我需要在给定行号的大文本文件中读取特定行(仅包含ASCII字符的多GB文件)。
到目前为止我做了什么:
由于文件没有相同大小的行,我处理文件以创建对应于行号(冷启动)的每行的偏移的Hashmap。随后,该偏移用于寻找随机访问文件(给定的文本文件)。这种方法的问题在于,对于非常大的文件大小,内存不足以容纳Hashmap,而且I / O成为瓶颈。我的系统规格是:8GB DDR2,1TB(SATA2)7200RPM,4-64位内核。我们假设整个硬件都在我手中。
我打算做什么
为了最大限度地减少延迟,我打算将文本文件中的所有行索引到页面中,并使用最近最少使用的页面替换策略将必要的页面分页到内存中,具体取决于包含所请求行的页面数字是否存在于内存中。 (就像缓存一样) 据我所知,很大程度上取决于页面大小和内存中常驻页面的数量,但我真的需要知道我是否朝着更有意义的方向前进,或者它是否只是一个过度杀伤?
感谢您的所有帮助和建议。
答案 0 :(得分:3)
每行偏移的Hashmap
这就是问题所在。地图可能很容易占用比文件本身更多的内存。
存储每个例如的偏移量第1024行需要1024倍的内存。从磁盘读取一行或一千行需要大约相同的时间,因为:
因此向下舍入到1024的倍数,找到该行并按顺序处理到您真正想要的行。
您正在使用HashMap<Integer, Integer>
,这会为盒装int
占用大量内存。但是你的密钥会构建一个序列,那么为什么不使用List<Integer>
甚至是int[]
?您可以将内存消耗减少4倍。
我按照以下方式访问List<int[]> offsets
:
int getOffset(int line) {
int listIndex = line >> 20; // one list entry per 1M lines
int arrayIndex = (line >> 10) & 1023; one array entry per 1k lines
int remaining = line & 1023; // lines to skip
// TODO: handling of index bounds
int offset = offsets.get(listIndex)[arrayIndex];
**seek to offset
**skip remaining lines
}
每1024行需要4个字节(int
),每1MiB需要更多内存。除非您的文本文件是多字节的,否则您不需要LRU,因为一切都很合适。
对于大文件,请在上面的文字中将int
替换为long
。