为什么我使用 FileChannel、ByteBuffer 和 CharBuffer 的方式与其他方式不一样?
Why doesn't my way of using FileChannel, ByteBuffer and CharBuffer work like the other way?
给定文件
Orange
Purple
Indigo
Pink
为什么下面代码中的 myWay
方法不能通过 Charset.decode
给我 ByteBuffer
的内容?请注意,我验证 ByteBuffer
具有文件内容,但似乎无论我在 myWay
中使用什么方法,我都无法让生成的 CharBuffer
具有内容。 otherWay
方法按预期工作。有谁知道发生了什么事?我已经阅读了 ByteBuffer and CharBuffer 的 javdoc,但没有真正看到任何解释这一点的内容(或者我只是错过了它。)如果我使用 FileChannel.read
与 FileChannel.map
会有什么区别可以用 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.");
}
}
输出:
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.
简单而微妙:您不会倒回缓冲区。
当你调用缓冲区的FileChannel#read(ByteBuffer)
, then this method will advance the position()
时:
System.out.println("Before "+buffer.position()); // prints 0
int bytesRead = channel.read(buffer);
System.out.println("After "+buffer.position()); // prints 28
当您随后将其解码为 CharBuffer
时,您实际上解码了那些从未被写入的 99 个字节(它们仍然是 0
)。
只需添加
buffer.rewind(); // (or buffer.position(0))
buffer.limit(bytesRead);
从文件通道中读取数据后,decode
方法会准确抓取已接收数据的部分。
给定文件
Orange Purple Indigo Pink
为什么下面代码中的 myWay
方法不能通过 Charset.decode
给我 ByteBuffer
的内容?请注意,我验证 ByteBuffer
具有文件内容,但似乎无论我在 myWay
中使用什么方法,我都无法让生成的 CharBuffer
具有内容。 otherWay
方法按预期工作。有谁知道发生了什么事?我已经阅读了 ByteBuffer and CharBuffer 的 javdoc,但没有真正看到任何解释这一点的内容(或者我只是错过了它。)如果我使用 FileChannel.read
与 FileChannel.map
会有什么区别可以用 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.");
}
}
输出:
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.
简单而微妙:您不会倒回缓冲区。
当你调用缓冲区的FileChannel#read(ByteBuffer)
, then this method will advance the position()
时:
System.out.println("Before "+buffer.position()); // prints 0
int bytesRead = channel.read(buffer);
System.out.println("After "+buffer.position()); // prints 28
当您随后将其解码为 CharBuffer
时,您实际上解码了那些从未被写入的 99 个字节(它们仍然是 0
)。
只需添加
buffer.rewind(); // (or buffer.position(0))
buffer.limit(bytesRead);
从文件通道中读取数据后,decode
方法会准确抓取已接收数据的部分。