Самый быстрый способ - это отобразить файл в сегмент памяти за сегментом (отображение большого файла в целом может вызвать нежелательные побочные эффекты).Это пропустит несколько относительно дорогих операций копирования.Операционная система загрузит файл в ОЗУ, а JRE представит его вашему приложению в виде области памяти вне кучи в виде ByteBuffer
.Обычно это позволяет вам сжать последние 2x / 3x производительности.
Для отображения в памяти требуется совсем немного вспомогательного кода (см. Фрагмент внизу), это не всегда лучший тактический способ.Вместо этого, если ваши входные данные основаны на строках и вам просто нужна разумная производительность (то, что у вас сейчас, вероятно, нет), просто сделайте что-то вроде:
import java.nio.Files;
import java.nio.Paths;
...
File.lines(Paths.get("/path/to/the/file"), StandardCharsets.ISO_8859_1)
// .parallel() // parallel processing is still possible
.forEach(line -> { /* your code goes here */ });
Для контраста, рабочий пример кода дляработа с файлом через отображение памяти будет выглядеть примерно так:В случае записей фиксированного размера (когда сегменты могут быть выбраны точно для соответствия границам записи) последующие сегменты могут обрабатываться параллельно.
static ByteBuffer mapFileSegment(FileChannel fileChannel, long fileSize, long regionOffset, long segmentSize) throws IOException {
long regionSize = min(segmentSize, fileSize - regionOffset);
// small last region prevention
final long remainingSize = fileSize - (regionOffset + regionSize);
if (remainingSize < segmentSize / 2) {
regionSize += remainingSize;
}
return fileChannel.map(FileChannel.MapMode.READ_ONLY, regionOffset, regionSize);
}
...
final ToIntFunction<ByteBuffer> consumer = ...
try (FileChannel fileChannel = FileChannel.open(Paths.get("/path/to/file", StandardOpenOption.READ)) {
final long fileSize = fileChannel.size();
long regionOffset = 0;
while (regionOffset < fileSize) {
final ByteBuffer regionBuffer = mapFileSegment(fileChannel, fileSize, regionOffset, segmentSize);
while (regionBuffer.hasRemaining()) {
final int usedBytes = consumer.applyAsInt(regionBuffer);
if (usedBytes == 0)
break;
}
regionOffset += regionBuffer.position();
}
} catch (IOException ex) {
throw new UncheckedIOException(ex);
}