Почему не работает метод array () MappedByteBuffer? - PullRequest
10 голосов
/ 21 декабря 2011

Я очень новичок в Java и пытаюсь использовать Java-интерфейс Mathematica для доступа к файлу с помощью отображения памяти (в надежде на повышение производительности).

Код Mathematica, который у меня есть (я считаю), эквивалентен следующему коду Java (основанному на this ):

import java.io.FileInputStream;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MainClass {
  private static final int LENGTH = 8*100;

  public static void main(String[] args) throws Exception {
    MappedByteBuffer buffer = new FileInputStream("test.bin").getChannel().map(FileChannel.MapMode.READ_ONLY, 0, LENGTH);
    buffer.load();
    buffer.isLoaded(); // returns false, why?
  }
}

Я хотел бы использовать метод array() в буфере, поэтому я пытаюсь загрузить содержимое буферов в память, используя load(). Однако даже после load(), isLoaded() возвращает false, а buffer.array() создает исключение: java.lang.UnsupportedOperationException at java.nio.ByteBuffer.array(ByteBuffer.java:940).

Почему не загружается буфер и как я могу вызвать метод array()?

Моя конечная цель - получить массив double с использованием asDoubleBuffer().array(). Метод getDouble() работает правильно, но я надеялся сделать это за один раз для хорошей производительности. Что я делаю не так?


Поскольку я делаю это из Mathematica, я опубликую фактический код Mathematica, который я тоже использовал (эквивалент вышеупомянутого в Java):

Needs["JLink`"]
LoadJavaClass["java.nio.channels.FileChannel$MapMode"]
buffer = JavaNew["java.io.FileInputStream", "test.bin"]@getChannel[]@map[FileChannel$MapMode`READUONLY, 0, 8*100]

buffer@load[]
buffer@isLoaded[] (* returns False *)

Ответы [ 2 ]

4 голосов
/ 21 декабря 2011

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

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

Мне кажется, что это связано с многими условиями и нежелательным поведением. Вам нужен именно этот класс?

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

FileChannel fChannel = new FileInputStream(f).getChannel();
    byte[] barray = new byte[(int) f.length()];
    ByteBuffer bb = ByteBuffer.wrap(barray);
    bb.order(ByteOrder.LITTLE_ENDIAN);
    fChannel.read(bb);

Работает со скоростью, почти равной скорости тестирования дисковой системы.

Для double вы можете использовать DoubleBuffer (с массивом double [], если размер f.length () / 4) или просто вызывать метод getDouble (int) из ByteBuffer.

0 голосов
/ 08 сентября 2017

в Java:

final byte[] hb;                  // Non-null only for heap buffers

, поэтому он даже не реализован для MappedByteBuffer, а предназначен для HeapByteBuffer.

в Android:

**
     * Child class implements this method to realize {@code array()}.
     *
     * @see #array()
     */
    abstract byte[] protectedArray();

и снова не вMappedByteBuffer, но, например, ByteArrayBuffer реализует резервный массив.

 @Override byte[] protectedArray() {
    if (isReadOnly) {
      throw new ReadOnlyBufferException();
    }
    return backingArray;
  }

Точка карты памяти должна быть вне кучи.Резервный массив будет в куче.
Если вы можете открыть FileChannel из RandomAccessFile и затем вызвать карту на канале, вы также можете использовать метод массового get () в MappedByteBuffer для чтения в байт [].Это копирует из кучи, избегая IO, в кучу снова.

buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
byte[] b = new byte[buffer.limit()];
buffer.get(b);
...