在java中使用MappedByteBuffer读取文件的每一行。

问题描述 投票:0回答:1

我正在做一个任务,在这个任务中,我必须读取一个巨大的文件(大小约为1.5 GB,约有1600万条记录)。我面前有2个选择。

  1. 使用BufferReader,我可以得到每一行的字符串。
  2. 使用MappedByteBuffer与FileChannel和RandomAccessFile。

在原始测试中,用选项1读取记录数需要2900毫秒,用选项2需要1450毫秒。

测试程序如下。

选项1:

public static void reviewBufferedReader () {
    long lineNumber = 0;
    String line = null;
    try (BufferedReader b = Files.newBufferedReader(Paths.get("D:\\\\Temp Data Files\\Data1.txt"), StandardCharsets.UTF_8)) {
        executor = RecordsDistributionExecutor.getInstance();
        while ((line = b.readLine()) != null) {
            lineNumber++;
        }
    } catch (Exception e) {
        System.err.println("Error in reviewBufferedReader : "+e.getMessage());
    } finally {

    }
    System.out.println("Total no. of lines: "+lineNumber);
}

选项2:

public static void reviewFileChannelWithMappedByteBuffer () {
    long lineNumber = 0;
    try (RandomAccessFile raFile = new RandomAccessFile("D:\\\\Temp Data Files\\Data2.txt", "r");
            FileChannel inChannel = raFile.getChannel();){
        MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY, 0, inChannel.size());
        buffer.load(); 
        char c;
        for(int i = 0; i< buffer.limit(); i++) {
            c = (char) buffer.get();
            if ('\n' == c) {
                lineNumber++;
            }
        }
        buffer.clear(); // do something with the data and clear/compact it.
    } catch (Exception e) {
        System.err.println("Error in reviewFileChannelWithMappedByteBuffer : "+e.getMessage());
    } finally {

    }
    System.out.println("Total no. of lines: "+lineNumber);
}

正如我所说,方案2的基本测试时间较少。

我有一个问题,在方案2中是否可以像方案1那样逐行读取文件数据。

谢谢。

Atul

java performance file nio
1个回答
0
投票

在user207421的评论后,我改变了我的答案。我建议使用BufferedReader和更大的默认缓冲区大小没有帮助。

 try(var reader = new BufferedReader(new FileReader(file), 128  * 1024)) { ... }

如果内存不是问题,Files.readAllBytes在我的PC上是最快的,可以计算0.5GB测试文件的行数,从NAS或SSD读取。

int lines = 0;
for (var b : Files.readAllBytes(f))
    if (b == '\n') lines++;

FileInputStream也不遑多让,而且内存消耗较少。

int len = 0, lines = 0;
byte[] buffer = new byte[128 * 1024];
try(var in = new FileInputStream(f)) {
    while (( len = in.read(buffer)) >= 0) {
        for (int x = len - 1 ; x >= 0 ; x--) {
            if (buffer[x] == '\n') lines++;
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.