Java – FileChannel returns the incorrect file size of the Assets folder Chinese

FileChannel returns the incorrect file size of the Assets folder Chinese… here is a solution to the problem.

FileChannel returns the incorrect file size of the Assets folder Chinese

I’m trying to use FileInputStream to read a File from the original folder in my Assets.

This is how I created FileInputStream:

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

After that, I tried reading data from 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 it won’t work. For some reason, fileChannel.size() returns a huge number. I have a test file that is exactly 13 bytes long, but fileChannel.size() returns 1126498! Also, if I ignore the size and start reading the returned bytes, it doesn’t match my test file at all!

So what’s going on here? Is there any way to fix this?

Solution

When your application is compiled, all resources are packaged into what is essentially a large file. To get data for only one File that you want to read, you must use the getStartOffset() and getDeclaredLength() Assets file descriptors. From >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 reading the entire File from start to finish, it is better to start reading data from the index returned by getStartOffset() and need to read as many bytes as 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 consider the case where getDeclaredLength() returns UNKNOWN_LENGTH, you can do this:

if(declaredLength == AssetFileDescriptor.UNKNOWN_LENGTH) {
    declaredLength = fileChannel.size() - startOffset;
}

Related Problems and Solutions