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

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

1. обзор

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

2. Как ошибаетсяMappedByteBuffer W

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

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

Одна вещь, с которой мы должны быть осторожны при использованииMappedByteBuffer, - это когда мы работаем с очень большими файлами с диска -we need to make sure the file will fit in memory.

В противном случае мы можем заполнить всю память и, как следствие, столкнуться с обычным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,aposition, из которого мы хотим читать, и параметрsize, который указывает, как сколько байтов мы хотим:

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 с помощью APIMappedByteBuffer. Для этого нам нужно открыть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 fileContent = Files.readAllLines(pathToWrite);
assertEquals(fileContent.get(0), "This will be written to the file");

5. Заключение

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

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

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