簡體   English   中英

為什么 MappedByteBuffer 的 array() 方法不起作用?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM