我是Java的新手,并尝试使用Mathematica的Java接口使用内存映射来访问文件(希望提高性能)。
我所拥有的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 *)
答案 0 :(得分:4)
据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(如果f.length()/ 4 size则使用double []数组)或者只调用ByteBuffer的getDouble(int)方法。
答案 1 :(得分:0)
:
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;
}
内存映射点应该是堆栈。支持数组将在堆上。
如果你可以从RandomAccessFile打开FileChannel,然后在通道上调用map,你也可以使用MappedByteBuffer上的批量get()方法读入byte []。这将从堆中复制,避免IO,再次进入堆。
buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
byte[] b = new byte[buffer.limit()];
buffer.get(b);