Search code examples
javabytebufferfilechannel

BufferUnderflowException while trying to read an Int from a binary file in Java


I am trying to read 4 bytes which represent an int, located at byte position 64 in a binary file.

This is what I have tried:

package testbinaryfile2;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

public class TestBinaryFile2 {

    public static void main(String[] args) throws IOException {
        
            FileChannel fc;    
            ByteBuffer indexField = ByteBuffer.allocate(4);
            
            fc = (FileChannel.open(Paths.get("myBinaryFile.bin"), StandardOpenOption.READ));                        
            fc.position(64);
            fc.read(indexField);
            System.out.println(indexField.getInt());
            
    }
            
}

This is the error I get:

run:
Exception in thread "main" java.nio.BufferUnderflowException
    at java.nio.Buffer.nextGetIndex(Buffer.java:509)
    at java.nio.HeapByteBuffer.getInt(HeapByteBuffer.java:373)
    at testbinaryfile2.TestBinaryFile2.main(TestBinaryFile2.java:30)
/home/user/.cache/netbeans/11.3/executor-snippets/run.xml:111: The following error occurred while executing this line:
/home/user/.cache/netbeans/11.3/executor-snippets/run.xml:94: Java returned: 1
BUILD FAILED (total time: 0 seconds)

Solution

  • After read indexField is pointing to its end, so it is necessary to use .rewind() method before getting the int.

    This code works:

    package testbinaryfile2;
    
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.FileChannel;
    import java.nio.file.Paths;
    import java.nio.file.StandardOpenOption;
    
    public class TestBinaryFile2 {
    
        public static void main(String[] args) throws IOException {
            
                FileChannel fc;    
                ByteBuffer indexField = ByteBuffer.allocate(4);
                
                fc = (FileChannel.open(Paths.get("myBinaryFile.bin"), StandardOpenOption.READ));                        
                fc.position(64);
                fc.read(indexField);
                indexField.rewind();    // <-- ADD THIS
                System.out.println(indexField.getInt());
                
        }
                
    }
    

    Additionally I got a suggestion to use mapped buffer:

      public static void main(String[] args) throws Exception {
        FileChannel fc = (FileChannel.open(Paths.get("myBinaryFile.bin"), StandardOpenOption.READ));
        MappedByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
        buffer.position(64);
        System.out.println(buffer.getInt());
      }
    

    But I am wondering if fc.map reads the whole file at once and uses as much memory as the size of the file.