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

Vin*_*ran 11 java randomaccessfile

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

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

Evg*_*eev 6

  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<String> 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);
}
Run Code Online (Sandbox Code Playgroud)

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

有两件事需要改进:

  1. 缓冲

  2. EOL识别