[英]Why doesn't the array() method of MappedByteBuffer work?
我對 Java 非常陌生,並嘗試使用 Mathematica 的 Java 接口來訪問使用內存映射的文件(希望能提高性能)。
我擁有的 Mathematica 代碼(我相信)等效於以下 Java 代碼(基於此):
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()
方法?
我的最終目標是使用asDoubleBuffer().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 *)
根據 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 大小,則使用double[] 數組)或僅調用ByteBuffer 的getDouble(int) 方法。
在 Java 中:
final byte[] hb; // Non-null only for heap buffers
所以它甚至不是為 MappedByteBuffer 實現的,而是為 HeapByteBuffer 實現的。
在安卓中:
**
* 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上的bulk get()方法讀入一個byte[]。 這會從堆外復制,避免 IO,再次復制到堆中。
buffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
byte[] b = new byte[buffer.limit()];
buffer.get(b);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.