java中的RandomAccessFile是否读取内存中的整个文件?

我需要读取一个大文件的最后n行(比如2GB)。 该文件是UTF-8编码的。

想知道最有效的方法。 在java中读取RandomAccessFile,但是seek()方法读取内存中的整个文件。 它使用本机实现,因此我无法引用源代码。

  1. RandomAccessFile.seek只设置文件指针的当前位置,没有字节被读入内存。

  2. 由于您的文件是UTF-8编码的,因此它是一个文本文件。 对于读取文本文件,我们通常使用BufferedReader,Java 7甚至添加了一个方便的方法File.newBufferedReader来创建BufferedReader的实例来从文件中读取文本。 尽管读取最后n行可能效率低,但易于实现。

  3. 为了提高效率,我们需要RandomAccessFile并从最后开始向后读取文件。 这是一个基本的例子

 public static void main(String[] args) throws Exception { int n = 3; List lines = new ArrayList<>(); try (RandomAccessFile f = new RandomAccessFile("test", "r")) { ByteArrayOutputStream bout = new ByteArrayOutputStream(); for (long length = f.length(), p = length - 1; p > 0 && lines.size() < n; p--) { f.seek(p); int b = f.read(); if (b == 10) { if (p < length - 1) { lines.add(0, getLine(bout)); bout.reset(); } } else if (b != 13) { bout.write(b); } } } System.out.println(lines); } static String getLine(ByteArrayOutputStream bout) { byte[] a = bout.toByteArray(); // reverse bytes for (int i = 0, j = a.length - 1; j > i; i++, j--) { byte tmp = a[j]; a[j] = a[i]; a[i] = tmp; } return new String(a); } 

它读取从tail到ByteArrayOutputStream的字节后的文件字节,当达到LF时,它会反转字节并创建一行。

有两件事需要改进:

  1. 缓冲

  2. EOL识别

如果您需要随机访问,则需要RandomAccessFile。 如果您知道自己在做什么,可以将从中获得的字节转换为UTF-8。

如果使用BuffredReader,则可以使用skip(n)字符数,这意味着它必须读取整个文件。


一种组合方式; 是使用带有skip()的FileInputStream,通过读回N个换行符找到要读取的位置,然后将流包装在BufferedReader中以读取具有UTF-8编码的行。