Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java - ByteBuffer.remaining() problems

Summary: I have a ByteBuffer in which I am pumping some data. After that, I want to send this data over a Socket.

So, I wrote code like this:

    private static void serialize(ByteBuffer buffer, EmployeeData emp, CharsetEncoder encoder)
{
    // id
    buffer.putInt(emp.getId());
    
    CharBuffer nameBuffer = CharBuffer.wrap(emp.getFirstName().toCharArray());
    ByteBuffer nbBuffer = null;
    
    // length of first name
    try
    {
        nbBuffer = encoder.encode(nameBuffer);
    } 
    catch(CharacterCodingException e)
    {
        throw new ArithmeticException();
    }

    System.out.println(String.format("String [%1$s] #bytes = %2$s", emp.getFirstName(), nbBuffer.limit()));
    buffer.putInt(nbBuffer.limit());
    buffer.put(nbBuffer);

    // put lastname
    nameBuffer = CharBuffer.wrap(emp.getLastName().toCharArray());
    nbBuffer = null;
    
    // length of first name
    try
    {
        nbBuffer = encoder.encode(nameBuffer);          
    } 
    catch(CharacterCodingException e)
    {
        throw new ArithmeticException();
    }

    System.out.println(String.format("String [%1$s] #bytes = %2$s", emp.getLastName(), nbBuffer.limit()));
    buffer.putInt(nbBuffer.limit());
    buffer.put(nbBuffer);
    
    // salary
    buffer.putInt(emp.getSalary());
}

In the calling code, I do the following. I first get the serialized ByteBuffer and then write it out to the socket...

            Socket client = new Socket("localhost", 8080);
        
        OutputStream oStream = client.getOutputStream();

        serialize(buffer, emp, encoder);
        
        buffer.rewind();            
        while(buffer.hasRemaining())
        {
            byte temp = buffer.get();
            ++ written;
        }
        
        buffer.rewind();
        System.out.println("#Bytes in output buffer: " + written + " limit = " + buffer.limit() + " pos = " + buffer.position() + " remaining = " + buffer.remaining());
        
        int remaining = buffer.remaining();
        while(remaining > 0)
        {
            oStream.write(buffer.get());
            -- remaining;
        }

I am expecting that buffer.remaining() should be exactly equal to the #bytes I pumped into the buffer. However I am finding that it is not, it is always equal to 1024, which is the size of the underlying array of the buffer.

This is how I create the buffer...

        Charset charset = Charset.forName("UTF-8");
    CharsetDecoder decoder = charset.newDecoder();
    CharsetEncoder encoder = charset.newEncoder();
    byte [] underlyingBuffer = new byte[1024];
    ByteBuffer buffer = ByteBuffer.wrap(underlyingBuffer);
    buffer.order(ByteOrder.LITTLE_ENDIAN);

This is what I get as the output of my print statement...

String [John] #bytes = 4 String [Smith] #bytes = 5

#Bytes in output buffer: 1024 limit = 1024 pos = 0 remaining = 1024

How can I get the exact #bytes that were put into the buffer?

Thanks!

like image 251
feroze Avatar asked Dec 14 '22 01:12

feroze


1 Answers

When you are done putting bytes into the buffer, you should flip it. You can probably do this in place of your first call to rewind instead.

A java.nio.Buffer distinguishes between capacity and limit. If you don't flip it, then limit and capacity are the same as the length of the array with which you initialized it.

By flipping it, the limit will be set to the end of the data you've encoded, and capacity will still be 1024. ByteBuffer#remaining looks at the delta between position and limit.

like image 173
Joe Holloway Avatar answered Dec 28 '22 18:12

Joe Holloway