[英]How to read line by line from mapped file in java using MappedByteBuffer
我想以非常快的方式閱讀一個大文件。 我正在使用這樣的MappedByteBuffer
:
String line = "";
try (RandomAccessFile file2 = new RandomAccessFile(new File(filename), "r"))
{
FileChannel fileChannel = file2.getChannel();
MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
for (int i = 0; i < buffer.limit(); i++)
{
char a = (char) buffer.get();
if (a == '\n'){
System.out.println(line);
line = "";
}else{
line += Character.toString(c);
}
}
這不能正常工作。 它正在更改文件的內容並打印更改的內容。 有沒有更好的方法來使用MappedByteBuffer讀取文件行?
最終我想分割線並提取某些內容(因為它的csv)所以這只是一個重現問題的最小例子。
我使用填充了隨機字符串的21 GB文件進行了一些測試,每行的長度為20-40個字符。 看起來內置的BufferedReader仍然是最快的方法。
File f = new File("sfs");
try(Stream<String> lines = Files.lines(f.toPath(), StandardCharsets.UTF_8)){
lines.forEach(line -> System.out.println(line));
} catch (IOException e) {}
將行讀取到流可確保您根據需要讀取行而不是一次讀取整個文件。
為了進一步提高速度,您可以通過適度因子增加BufferedReader的緩沖區大小。 在我的測試中,它的啟動速度超過了大約1000萬行的正常緩沖區大小。
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
int size = 8192 * 16;
try (BufferedReader br = new BufferedReader(new InputStreamReader(newInputStream(f.toPath()), decoder), size)) {
br.lines().limit(LINES_TO_READ).forEach(s -> {
});
} catch (IOException e) {
e.printStackTrace();
}
我用來測試的代碼:
private static long LINES_TO_READ = 10_000_000;
private static void java8Stream(File f) {
long startTime = System.nanoTime();
try (Stream<String> lines = Files.lines(f.toPath(), StandardCharsets.UTF_8).limit(LINES_TO_READ)) {
lines.forEach(line -> {
});
} catch (IOException e) {
e.printStackTrace();
}
long endTime = System.nanoTime();
System.out.println("no buffer took " + (endTime - startTime) + " nanoseconds");
}
private static void streamWithLargeBuffer(File f) {
long startTime = System.nanoTime();
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
int size = 8192 * 16;
try (BufferedReader br = new BufferedReader(new InputStreamReader(newInputStream(f.toPath()), decoder), size)) {
br.lines().limit(LINES_TO_READ).forEach(s -> {
});
} catch (IOException e) {
e.printStackTrace();
}
long endTime = System.nanoTime();
System.out.println("using large buffer took " + (endTime - startTime) + " nanoseconds");
}
private static void memoryMappedFile(File f) {
CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
long linesReadCount = 0;
String line = "";
long startTime = System.nanoTime();
try (RandomAccessFile file2 = new RandomAccessFile(f, "r")) {
FileChannel fileChannel = file2.getChannel();
MappedByteBuffer buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0L, Integer.MAX_VALUE - 10_000_000);
CharBuffer decodedBuffer = decoder.decode(buffer);
for (int i = 0; i < decodedBuffer.limit(); i++) {
char a = decodedBuffer.get();
if (a == '\n') {
line = "";
} else {
line += Character.toString(a);
}
if (linesReadCount++ >= LINES_TO_READ){
break;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
long endTime = System.nanoTime();
System.out.println("using memory mapped files took " + (endTime - startTime) + " nanoseconds");
}
順便說一下,我注意到如果映射文件大於Integer.MAX_VALUE, FileChannel.map會拋出異常 ,這使得該方法對於讀取非常大的文件是不切實際的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.