从内存映射文件中读取意外值

时间:2016-08-04 19:12:19

标签: android nio

我正在映射这样的文件:

try(AssetFileDescriptor fd = mContext.getAssets().openFd("AZ_SMA.shp");
        FileInputStream shp = fd.createInputStream();
        FileChannel ch = shp.getChannel()) {
    ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY,
                0, ch.size());
    // do stuff with buffer
}

AssetManager#openFd(...)最初投掷java.io.FileNotFoundException: This file can not be opened as a file descriptor; it is probably compressed,直到我将其添加到build.gradle

android {
    aaptOptions {
        noCompress "shp"
    }
    ...
}

现在它打开了,但我正在读垃圾。如文件名所示,该文件是Esri形状文件。该文件的前四个字节应该是00 00 27 0A,我已经在十六进制编辑器中验证了这一点。但我正在将它们视为50 4B 03 04,或以小数形式显示80 75 03 04

final byte[] bytes = new byte[4];
buffer.get(bytes);
Log.d("DERP", Arrays.toString(bytes));
  

08-04 12:01:53.951 12051-12267 / com.chalcodes.shapefiles D / DERP:[80,75,3,4]

我做错了什么?

1 个答案:

答案 0 :(得分:0)

一位朋友建议我应该验证文件的长度。点击它的时候。

AssetFileDescriptor返回的AssetManager#openFd(...)描述了包含映射文件的APK块,而不是文件本身。我的原始文件是13,401,744字节,但buffer.limit()返回15,234,522。

解决方案是改变这个:

ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY,
    0, ch.size());

......对此:

ByteBuffer buffer = ch.map(FileChannel.MapMode.READ_ONLY,
    fd.getStartOffset(), fd.getLength());

我不太清楚AssetFileDescriptor' getLength()getDeclaredLength()之间的区别,但这有效。前四个字节是我的预期,buffer.limit()返回预期的文件大小。