Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't the array() method of MappedByteBuffer work?

I am very new to Java, and trying to use Mathematica's Java interface to access a file using memory mapping (in hope of a performance improvement).

The Mathematica code I have is (I believe) equivalent to the following Java code (based on 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?
  }
}

I would like to use the array() method on buffer, so I am trying to load the buffers contents into memory first using load(). However, even after load(), isLoaded() returns false, and buffer.array() throws an exception: java.lang.UnsupportedOperationException at java.nio.ByteBuffer.array(ByteBuffer.java:940).

Why doesn't the buffer load and how can I call the array() method?

My ultimate aim here is to get an array of doubles using asDoubleBuffer().array(). The method getDouble() does work correctly, but I was hoping to get this done in one go for good performance. What am I doing wrong?


As I am doing this from Mathematica, I'll post the actual Mathematica code I used too (equivalent to the above in 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 *)
like image 300
Szabolcs Avatar asked Dec 21 '11 15:12

Szabolcs


1 Answers

According to Javadoc
"The content of a mapped byte buffer can change at any time, for example if the content of the corresponding region of the mapped file is changed by this program or another. Whether or not such changes occur, and when they occur, is operating-system dependent and therefore unspecified.

All or part of a mapped byte buffer may become inaccessible at any time, for example if the mapped file is truncated. An attempt to access an inaccessible region of a mapped byte buffer will not change the buffer's content and will cause an unspecified exception to be thrown either at the time of the access or at some later time. It is therefore strongly recommended that appropriate precautions be taken to avoid the manipulation of a mapped file by this program, or by a concurrently running program, except to read or write the file's content."

To me it seems to many conditions and undesirable misbehavior. Do you need particularly this class?

If you just need to read file contents in fastest way, give a try:

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);

It works at speed almost equal to disk system test speed.

For double you can use DoubleBuffer (with double[] array if f.length()/4 size) or just call getDouble(int) method of ByteBuffer.

like image 65
andrey Avatar answered Nov 15 '22 18:11

andrey