Перейти к основному содержимому

Использование Java MappedByteBuffer

· 3 мин. чтения

1. Обзор

В этой быстрой статье мы рассмотрим MappedByteBuffer в пакете java.nio . Эта утилита может быть очень полезна для эффективного чтения файлов.

2. Как работает MappedByteBuffer

Когда мы загружаем область файла, мы можем загрузить ее в конкретную область памяти, к которой можно получить доступ позже.

Когда мы знаем, что нам нужно будет прочитать содержимое файла несколько раз, хорошей идеей будет оптимизировать дорогостоящий процесс, например, сохранив это содержимое в памяти. Благодаря этому последующие поиски этой части файла будут выполняться только в основной памяти без необходимости загрузки данных с диска, что существенно снижает задержку.

Одна вещь, с которой мы должны быть осторожны при использовании MappedByteBuffer , — это когда мы работаем с очень большими файлами с диска — нам нужно убедиться, что файл поместится в памяти .

В противном случае мы можем заполнить всю память и, как следствие, нарваться на обычное OutOfMemoryException. Мы можем преодолеть это, загрузив только часть файла, например, на основе шаблонов использования.

3. Чтение файла с помощью MappedByteBuffer

Допустим, у нас есть файл с именем fileToRead.txt со следующим содержимым:

This is a content of the file

Файл находится в каталоге /resource , поэтому мы можем загрузить его с помощью следующей функции:

Path getFileURIFromResources(String fileName) throws Exception {
ClassLoader classLoader = getClass().getClassLoader();
return Paths.get(classLoader.getResource(fileName).getPath());
}

Чтобы создать MappedByteBuffer из файла, сначала нам нужно создать из него FileChannel . Как только мы создали наш канал, мы можем вызвать для него метод map() , передав MapMode, позицию , из которой мы хотим прочитать, и параметр размера , который указывает, сколько байтов мы хотим:

CharBuffer charBuffer = null;
Path pathToRead = getFileURIFromResources("fileToRead.txt");

try (FileChannel fileChannel (FileChannel) Files.newByteChannel(
pathToRead, EnumSet.of(StandardOpenOption.READ))) {

MappedByteBuffer mappedByteBuffer = fileChannel
.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());

if (mappedByteBuffer != null) {
charBuffer = Charset.forName("UTF-8").decode(mappedByteBuffer);
}
}

После того, как мы отобразили наш файл в отображенный в память буфер, мы можем прочитать данные из него в CharBuffer. Важно отметить, что хотя мы читаем содержимое файла, когда вызываем метод decode () с передачей MappedByteBuffer, мы читаем из памяти, а не с диска. Поэтому это чтение будет очень быстрым.

Мы можем утверждать, что содержимое, которое мы читаем из нашего файла, является фактическим содержимым файла fileToRead.txt :

assertNotNull(charBuffer);
assertEquals(
charBuffer.toString(), "This is a content of the file");

Каждое последующее чтение из mappedByteBuffer будет очень быстрым, поскольку содержимое файла отображается в памяти, и чтение выполняется без необходимости поиска данных на диске.

4. Запись в файл с помощью MappedByteBuffer

Допустим, мы хотим записать некоторый контент в файл fileToWriteTo.txt с помощью API MappedByteBuffer . Для этого нам нужно открыть FileChannel и вызвать для него метод map() , передав FileChannel.MapMode.READ_WRITE.

Затем мы можем сохранить содержимое CharBuffer в файл, используя метод put() из MappedByteBuffer:

CharBuffer charBuffer = CharBuffer
.wrap("This will be written to the file");
Path pathToWrite = getFileURIFromResources("fileToWriteTo.txt");

try (FileChannel fileChannel = (FileChannel) Files
.newByteChannel(pathToWrite, EnumSet.of(
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING))) {

MappedByteBuffer mappedByteBuffer = fileChannel
.map(FileChannel.MapMode.READ_WRITE, 0, charBuffer.length());

if (mappedByteBuffer != null) {
mappedByteBuffer.put(
Charset.forName("utf-8").encode(charBuffer));
}
}

Мы можем утверждать, что фактическое содержимое charBuffer было записано в файл, прочитав его содержимое:

List<String> fileContent = Files.readAllLines(pathToWrite);
assertEquals(fileContent.get(0), "This will be written to the file");

5. Вывод

В этом кратком руководстве мы рассмотрели конструкцию MappedByteBuffer из пакета java.nio .

Это очень эффективный способ чтения содержимого файла несколько раз, так как файл отображается в память, и при последующих операциях чтения не нужно каждый раз обращаться к диску.

Все эти примеры и фрагменты кода можно найти на GitHub — это проект Maven, поэтому его легко импортировать и запускать как есть.