简体   繁体   中英

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

Given the file

Orange
Purple
Indigo
Pink

Why won't the myWay method in the code below give me the content of the ByteBuffer via the Charset.decode ? Notice I validate that the ByteBuffer has the file content, but it seems no matter what methodology I use from within myWay , I cannot get the generated CharBuffer to have the content. The otherWay method works as expected. Does anyone know what's going on? I've read the javdoc for ByteBuffer and CharBuffer but didn't really see anything that explains this (or I just missed it.) What difference would it make to use FileChannel.read vs FileChannel.map if I can show the content 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.");
    }
}

The 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.

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

When you call FileChannel#read(ByteBuffer) , then this method will advance the position() of the buffer:

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

When you afterwards decode this into a CharBuffer , then you essentially decode exactly those 99 bytes that have never been written to (and that are all still 0 ).


Just add

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

after you have read the data from the file channel, so that the decode method grabs exactly the part that has received data.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM