Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FileChannel returns wrong file size of file in assets folder

I am trying to read a File from the raw folder in my assets using a FileInputStream.

This is how I create the FileInputStream:

AssetManager assetManager = getAssets();
AssetFileDescriptor fileDescriptor = assetManager.openFd(fileName);
FileInputStream inputStream = new FileInputStream(fileDescriptor.getFileDescriptor());

After that I am trying to read the data from the File like this:

FileChannel fileChannel = inputStream.getChannel();

MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size());
IntBuffer intBuffer = mappedByteBuffer.asIntBuffer();

int[] array = new int[intBuffer.limit()];
intBuffer.get(array);

inputStream.close();
fileChannel.close();

But this does not work. For some reason fileChannel.size() returns a huge number. I have a test file which is exactly 13 bytes long, but fileChannel.size() returns 1126498! And additionally if I ignore the size and just start reading the returned bytes don't match my test file at all!

So what is going on here? And is there a way I can fix this?

like image 603
hotHead Avatar asked Sep 27 '22 21:09

hotHead


1 Answers

When your app is compiled all resources are packaged together into what is essentially one big File. To get just the data of the one File you want to read you have to use getStartOffset() and getDeclaredLength() of the AssetFileDescriptor. From the documentation:

  • getStartOffset(): Returns the byte offset where this asset entry's data starts.
  • getDeclaredLength(): Return the actual number of bytes that were declared when the AssetFileDescriptor was constructed. Will be UNKNOWN_LENGTH if the length was not declared, meaning data should be read to the end of the file.

So instead of just reading the whole File from start to finish you just need to read the data starting at the index returned by getStartOffset() and you need to read as many bytes as are returned by getDeclaredLength(). Try something like this:

long startOffset = fileDescriptor.getStartOffset();
long declaredLength = fileDescriptor.getDeclaredLength();
MappedByteBuffer mappedByteBuffer = fileChannel.map(
        FileChannel.MapMode.READ_ONLY, 
        startOffset, 
        declaredLength);

If you want to account for the case in which getDeclaredLength() returns UNKNOWN_LENGTH you can just do this:

if(declaredLength == AssetFileDescriptor.UNKNOWN_LENGTH) {
    declaredLength = fileChannel.size() - startOffset;
}
like image 190
Xaver Kapeller Avatar answered Oct 12 '22 22:10

Xaver Kapeller