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() на нем, передавая в режиме Map, позицию , из которой мы хотим читать, и параметр 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); } }
Как только мы сопоставили наш файл с буфером памяти, мы можем прочитать данные из него в буфер Char. Важно отметить, что, хотя мы читаем содержимое файла при вызове метода decode () , передающего MappedByteBuffer, мы читаем из памяти, а не с диска. Поэтому это чтение будет очень быстрым.
Мы можем утверждать, что содержимое, которое мы читаем из вашего файла, является фактическим содержимым fileToRead.txt файл:
assertNotNull(charBuffer); assertEquals( charBuffer.toString(), "This is a content of the file");
Каждое последующее чтение из MappedByteBuffer будет очень быстрым, поскольку содержимое файла отображается в памяти, и чтение выполняется без необходимости поиска данных с диска.
4. Запись в файл с помощью MappedByteBuffer
Допустим, мы хотим записать какой-то контент в файл fileToWriteTo.txt с помощью MappedByteBuffer API. Для этого нам нужно открыть файловый канал и вызвать на нем метод map () , передав его в файловый канал.MapMode.READ_WRITE.
Затем мы можем сохранить содержимое буфера Char в файл с помощью метода 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 было записано в файл, прочитав его содержимое:
ListfileContent = Files.readAllLines(pathToWrite); assertEquals(fileContent.get(0), "This will be written to the file");
5. Заключение
В этом кратком руководстве мы рассматривали конструкцию MappedByteBuffer из пакета java.nio .
Это очень эффективный способ чтения содержимого файла несколько раз, так как файл отображается в память, и последующие чтения не нужно каждый раз переносить на диск.
Все эти примеры и фрагменты кода можно найти на GitHub – это проект Maven, поэтому его должно быть легко импортировать и запускать как есть.