【问题标题】:Reading specific lines from a large file in Java从Java中的大文件中读取特定行
【发布时间】:2014-10-13 13:33:23
【问题描述】:

我目前正在做一个文件处理练习,我需要在给定行号的情况下读取一个巨大的文本文件中的特定行(仅包含 ASCII 字符的多 GB 文件)。

到目前为止我做了什么:

由于文件没有大小相等的行,我对文件进行处理以创建与行号相对应的每行偏移量的哈希图(冷启动)。随后,偏移量用于寻找随机访问文件(给定的文本文件)。这种方法的问题在于,对于非常大的文件大小,内存不足以容纳 Hashmap,而且 I/O 成为瓶颈。我的系统规格是:8GB DDR2、1TB(SATA2) 7200RPM、4-64 位内核。让我们假设整个硬件都由我支配。

我打算做什么

为了最小化延迟,我打算将文本文件中的所有行索引到页面中,并使用最近最少使用的页面替换策略将必要的页面分页到内存中,具体取决于页面是否包含请求的行数字是否存在于内存中。 (就像缓存一样) 我知道这在很大程度上取决于页面大小和内存中常驻页面的数量,但我真的需要知道我是否正在朝着更有意义的方向前进,或者这是否只是矫枉过正?

感谢您的所有帮助和建议。

【问题讨论】:

  • 是否必须按行号或什么条件访问文件?
  • 是的,文件是按行号访问的。感谢您的澄清,我已经编辑了帖子
  • 在考虑缓存策略之前:后续读取多次访问相同的行号是否常见?
  • 没有这样的假设。我的想法是基于这样一个事实,即即使以页的形式存储在内存中的一百万行产生一小部分成功读取,由于 I/O 导致的延迟也可以减少。

标签: java performance file-io


【解决方案1】:

每行偏移的哈希图

这就是问题所在。地图很容易比文件本身占用更多的内存。

存储每个例如的偏移量第 1024 行将需要少 1024 倍的内存。从磁盘读取一行或一千行大约需要相同的时间,因为:

  • 最小的可访问单元是块(以前是 512 B,但现在是 4KiB)
  • 与寻道时间相比,块的传输时间可以忽略不计

所以向下舍入到 1024 的倍数,找到行并按顺序处理到您真正想要的行。


您正在使用HashMap<Integer, Integer>,它占用大量内存用于装箱的ints。但是您的密钥构建了一个序列,那么为什么不使用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 需要更多内存。除非您的文本文件是多 TB,否则您不需要 LRU,因为一切都非常适合。

对于大文件,将上述文本中的int 替换为long

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-06-03
  • 2012-01-22
  • 1970-01-01
  • 2011-01-09
  • 1970-01-01
  • 2013-08-03
  • 1970-01-01
相关资源
最近更新 更多