首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >当您知道行号时,从一个非常大的文件中读取一行的最快方法是什么?

当您知道行号时,从一个非常大的文件中读取一行的最快方法是什么?
EN

Stack Overflow用户
提问于 2022-03-12 02:15:20
回答 3查看 636关注 0票数 0

首先,我逐行遍历文件,然后在数组中跟踪特定的行号,稍后需要引用这些数字。

该文件非常大(例如1GB或更多),因此我扫描它并将特定的行号加载到数组中,该文件不再在内存中。

在文件中读取特定行的最快和最有效的方法是什么?

该文件包含字符串文本的换行符,其中每一行代表一个事务。

与行号不同,以某种方式存储字节偏移量是否更有意义?

EN

回答 3

Stack Overflow用户

发布于 2022-03-12 03:06:33

当您知道行号时,从一个非常大的文件中读取一行的最快方法是什么?

以下假设文件太大,无法作为数据结构或内存映射保存在内存中。

如果您只知道行号和,您只读取一行,那么最快(简单)的方法是使用BufferedReader.read读取并计数行分隔符。

如果您要对每个文件执行多次操作,那么更复杂的是高效地执行此操作。首先,您需要一个数据结构来映射行号到文件偏移量。这必须通过读取文件、计数行和记录字节偏移量来创建。有多种表示方法,但是一组偏移量将是内存效率最高的.如果你只打算用它把一个行号映射到一个字节偏移量的话,速度最快。

不幸的是,使用Reader,您无法从当前字节偏移量中获取当前字节偏移量,也无法“查找”特定字节或字符偏移量的Reader

因此,要实现高效的行--没有->字节偏移量的->行--文本检索,您需要使用BufferedInputStream或类似的。但是,您还需要让代码知道正在读取的文件的字符集:

  1. 您将需要使用new String(byte[], ..., Charset)和/或CharsetCharsetDecoder API将组成一行的字节转换为String对象。
  2. 如果您决定使用read(byte[], ...)ByteBuffer来提高效率,则需要小心不要在转换为字符串时破坏跨越缓冲区边界的多字节字符。
  3. 理论上,您的代码还需要以编码识别的方式检测行分隔符。在一些字符集中,对于ASCII、NL和CR字节值的简单编码无关测试将无法工作。这方面存在问题的例子包括EBCDIC (它使用0x15作为NL的代码)和UTF-16编码(其中CR和NL表示为2个字节而不是一个字节)。

这可不是小事..。

第二个问题是,每次应用程序用给定的行号读取行时,它首先需要“查找”流到正确的字节偏移量。根据访问模式的不同,这可能需要seek系统调用,然后是read系统调用。根据访问模式的不同,最好实现某种类型的缓存。你可以把你读到的那一行.或者,您可以在磁盘块边界和缓存前面和/或以下行进行读取。最佳策略将取决于访问模式等,而且可能只能通过实验确定。

(在数据库中存储行可能更简单和/或更有效,而不是从1GB+文本文件中读取。数据库通常会为您执行一些服务器端缓存,并且实现客户端缓存的方法多种多样。)

票数 2
EN

Stack Overflow用户

发布于 2022-03-14 23:23:07

这个问题有点不清楚,所以我将提出多种可能性,并对每种可能性提出解决方案。

我跟踪特定的线路号码,我需要以后参考。

您知道在开始之前需要检索的所有行吗?或者有某种机制来识别这些线?

如果是,那么最简单的解决方案是使用BufferedReader.readLine()读取文件一次。将检索到的每一行存储在Map中,并按其行号进行键控。

该文件非常大(例如,1GB或更多)

在这个大小下,我实际上将整个文件读入Map -- 1GB没有那么大。我可能会使用TreeMap,因为它的内部结构比HashMap稍小,而且性能上的差别并不明显。

与行号不同,以某种方式存储字节偏移量是否更有意义?

是的,事实上这就是你必须做的。事实上,我会存储每一行的开始和结束偏移量,但是您可以只存储开始--结束是下一行的开始- 1。

long[]中存储将是最有效的,因为ArrayList<Long>会为每个条目设置对象开销。但是,对于前者,您必须分配一个大于可能行数的数组,并且/或自行处理调整大小的操作。

您需要读取整个文件才能确定行分隔符。但是,只要文件使用标准的\n (或\r)行分隔符,并且使用与uses兼容的编码(例如,iso-8859-x、utf-8,甚至utf-16/utf-32,只要注意读取大小),那么在读取文件时不需要进行任何字符集翻译。

我会使用BufferedInputStream,一次读一个字符。这意味着从数组中检索单个字节,因此至少要尽可能快地完成--至少使用java.io

如果您的文件小于2GB,则可以使用MappedByteBuffer。这将在一次读取一个字节时稍微提高性能,因为它不需要将字节从OS缓冲区复制到Java堆上。它还利用操作系统读取和缓存页面,这可能导致更高效的读取(例如,因为操作系统决定一次读取多个块)。

要读取行,需要查找起始偏移量,获取其与结束偏移量之间的字节,然后调用new String(b, charset)

如果您不使用MappedByteBuffer,那么我建议使用FileChannel而不是RandomAccessFile。这也将利用页面缓存(尽管程度较小),并且不需要对每次读取都使用syscall。

票数 0
EN

Stack Overflow用户

发布于 2022-03-12 02:33:10

您可以使用BufferedReader从文件中读取,它比其他方式更可靠。如果我简单地说,如果您要求使用BufferedReader读取一行--它一次读取多行,但它给了您要查找的行--其余的行存储在缓冲区中,当您再次请求另一行时,它将检查缓冲区中是否存在行--它将从缓冲区中给出该行,它不会每次都进入已保存的内存从文件中读取。

BufferedReader.readLine()

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71446467

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档