Java 如何从一个大文件中读取任意但连续的n行

Java 如何从一个大文件中读取任意但连续的n行,java,Java,我想读任意数量的行。这些文件目前是普通ascii文本文件(稍后可能是UTF8/多字节字符文件) 因此,我想要的是一个方法只读取特定行的文件(例如从101-200),并且在这样做时,它不应该阻止任何事情(即,对于201-210,同一个文件可以被另一个线程读取,并且不应该等待第一次读取操作) 如果没有要读取的行,它应该优雅地返回它可以读取的内容。方法的输出可以是一个列表 到目前为止,我想到的解决方案是首先读取整个文件,以找到行数以及每个新行字符的字节位置。然后使用RandomAccessFile读取

我想读任意数量的行。这些文件目前是普通ascii文本文件(稍后可能是UTF8/多字节字符文件)

因此,我想要的是一个方法只读取特定行的文件(例如从101-200),并且在这样做时,它不应该阻止任何事情(即,对于201-210,同一个文件可以被另一个线程读取,并且不应该等待第一次读取操作)

如果没有要读取的行,它应该优雅地返回它可以读取的内容。方法的输出可以是一个列表

到目前为止,我想到的解决方案是首先读取整个文件,以找到行数以及每个新行字符的字节位置。然后使用RandomAccessFile读取字节并将其转换为行。我必须将字节转换为字符串(但这可以在读取完成后完成)。通过适当的簿记,我可以避免读取文件以外的文件时出现文件结尾异常。解决方案效率有点低,因为它确实会对文件进行两次检查,但文件大小可能非常大,我们希望在内存中保留很少的内容

如果有这样一个库可以工作,但是一个更简单的原生java解决方案会更好


像往常一样,我很感激你提出的澄清问题,我会继续编辑这个问题。

为什么不使用hasNextLine()并循环浏览,直到达到你想要的数量,然后抓取你想要的任意多行……如果它用完了,它将优雅地失败。这样,你只需要阅读一次文件(除非扫描器能完全读取……我从来没有看过引擎盖下面……但听起来你并不在意,所以……给你:)

如果您想最大限度地减少内存消耗,我会使用内存映射文件。这几乎不使用堆。存储在内存中的文件量由操作系统处理,因此您无需自行调整行为

FileChannel fc = new FileInputStream(fileName).getChannel();
final MappedByteBuffer map = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
如果你有一个2 GB或更高的文件,你需要多个映射。在最简单的情况下,你可以扫描数据并记住所有索引。索引本身可能占用大量空间,因此你可能只记住每N个,例如每10个

e、 一个有40字节行的2GB文件可能有5000万行,需要400 MB的内存

拥有大索引的另一种方法是创建另一个内存映射文件

FileChannel fc = new RandomAccessFile(fileName).getChannel();
final MappedByteBuffer map2 = fc.map(FileChannel.MapMode.READ_WRITE, 0, fc.size()/10);
问题是,在开始之前,您不知道文件需要有多大。幸运的是,如果您使其比需要的大,它不会消耗内存或磁盘空间,因此最简单的方法是将其变大,并在知道需要的大小时将其截断

这还可以用于避免每次加载文件时(仅当文件发生更改时)重新索引该文件。如果文件仅附加到,则每次都可以从文件末尾开始索引


注意:使用这种方法可能会使用大量虚拟内存,对于64位JVM,这是没有问题的,因为您的限制可能为256 TB。对于32位应用程序,您的限制可能为1.5-3.5 GB,具体取决于您的操作系统。

获取行数很容易,但我不知道如何使用扫描仪跳过前n行而不迭代o我没说你可以,但我认为扫描器愿意非常快地向前移动它的行索引,所以,你循环寻找你想要的行:while(myScanner.hasNextLine()&¤tLine++