Why doesn't my way of using FileChannel, ByteBuffer and CharBuffer work the same?

Given the file

Orange
Purple
Indigo
Pink

Why is the method myWay

in the code below not giving me content ByteBuffer

through Charset.decode

? Note that I am checking what the ByteBuffer

content of the file has, but it seems that no matter what methodology I use from myWay

, I cannot get the generated CharBuffer

content. The method otherWay

works as expected. Does anyone know what's going on? I read the javdoc for ByteBuffer and CharBuffer but didn't really see anything that explains it (or I just missed it.) What's the difference if I used FileChannel.read

vs FileChannel.map

if I can show the contents of the buffer with read

?

public class Junk {
    private static final int BUFFER_SIZE = 127;
    private static final String CHARSET = "UTF-8";

    public static void main(String[] args) {
        try {
            String fileName = "two.txt";
            myWay(fileName);
            otherWay(fileName);
        } catch (IOException e) {
            throw new IllegalStateException(e);
        }
    }

    private static void myWay(String fileName) throws IOException {
        System.out.println("I did it MY WAY!......");
        FileChannel channel = FileChannel.open(Paths.get(fileName), StandardOpenOption.READ);
        // I tried both `allocate` and `allocateDirect`
        ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE);
        int bytesRead = channel.read(buffer);
        channel.close();
        // Manually build the string from the ByteBuffer.
        // This is ONLY to validate the buffer has the content
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<bytesRead;i++){
            sb.append((char)buffer.get(i));
        }
        System.out.println("manual string='"+sb+"'");

        CharBuffer charBuffer = Charset.forName(CHARSET).decode(buffer);
        // WHY FOR YOU NO HAVE THE CHARS??!!
        System.out.println("CharBuffer='" + new String(charBuffer.array()) + "'");
        System.out.println("CharBuffer='" + charBuffer.toString() + "'");
        System.out.println("........My way sucks.");
    }

    private static void otherWay(String fileName) throws IOException{
        System.out.println("The other way...");
        FileChannel channel = FileChannel.open(Paths.get(fileName), StandardOpenOption.READ);
        ByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
        channel.close();
        Charset chars = Charset.forName(CHARSET);
        CharBuffer cbuf = chars.decode(buffer);
        String str = new String(cbuf.array());
        System.out.println("str = '" + str + "'");
        System.out.println("...works.");
    }
}

      

Output:

I did it MY WAY! ......
manual string = 'Orange
Purple
Indigo
Pink '
CharBuffer = ''
CharBuffer = ''
........ My way sucks.
The other way ...
str = 'Orange
Purple
Indigo
Pink '
... works.
+3


source to share


1 answer


Simple and subtle: you don't rewind your buffer.

When you call FileChannel#read(ByteBuffer)

this method will advance the position()

buffers:

System.out.println("Before "+buffer.position()); // prints 0
int bytesRead = channel.read(buffer);
System.out.println("After  "+buffer.position()); // prints 28

      

When you subsequently decode that into CharBuffer

, then you are essentially decoding exactly the 99 bytes that were never written (and they are all still 0

).




Just add

buffer.rewind(); // (or buffer.position(0))
buffer.limit(bytesRead);

      

after you've read data from the file pipe, so the method decode

grabs exactly the part that received the data.

+4


source







All Articles