SeekableByteChannel 俄语字符
SeekableByteChannel russian chars
最近我开始学习java.nio。我在教科书中有一个例子,如何使用 SeekableByteChannel:
读取文本文件
int count;
Path path;
try {
path = Paths.get(System.getProperty("user.home") + "/desktop/text.txt");
} catch (InvalidPathException e) {
out.println(e.getMessage());
return;
}
try (SeekableByteChannel channel = Files.newByteChannel(path)) {
ByteBuffer buffer = ByteBuffer.allocate(128);
do {
count = channel.read(buffer);
if (count != -1) {
buffer.rewind();
for (int i = 0; i < count; i++)
out.print((char) buffer.get());
}
} while (count != -1);
} catch (IOException e) {
out.println("File not found!!!");
}
out.flush();
所以我使用 ANSI 编码制作了一个包含英语和俄语单词的文本文件。这就是我得到的:
方法buffer.get()returnsbyte值和俄文字符从1000开始。所以我已将编码更改为 UTF-8 并使用另一种方法:
for (int i = 0; i < count; i += 2)
out.print(buffer.getChar()); //reads 2 bytes and converts them to char
但这给了我一行问号。
那么有人知道如何使用 SeekableByteChannel 正确阅读俄语文本吗?
ByteBuffer
的方法getChar()
读取两个字节,并解释为char
的高字节和低字节,也就是说,总是使用UTF-16
编码。一般来说,你不应该尝试手动将字节拼凑成 String
s,旧的 I/O API 和 NIO 都不行。仅提及在尝试手动解码缓冲区中的字节时必须处理的一件事,即缓冲区中的字节可能不会在多字节编码的字符边界处结束。
如果您想从 SeekableByteChannel
中读取文本,您可以使用 Channels.newReader(…)
构造一个 Reader
使用指定的字符集来解码字节。
但是,当然,您可以完全跳过 Channel
内容并使用 Files.newBufferedReader(…)
从 Path
.
创建一个 Reader
顺便说一句,示例代码是有问题的,即使是读取字节序列也是如此。这是一个简化的例子:
Path path=Paths.get(System.getProperty("user.home")).resolve("desktop/text.txt");
try(FileChannel channel=FileChannel.open(path)) {
ByteBuffer buffer = ByteBuffer.allocate(128);
while(channel.read(buffer)!=-1) {
buffer.flip();
while(buffer.hasRemaining())
System.out.printf("%02x ", buffer.get());
buffer.clear();
System.out.println();
}
} catch (IOException e) {
System.out.println(e.toString());
}
A ByteBuffer
知道它包含多少字节(即已通过读取操作放入其中)。使用 flip
可以准备缓冲区以读出它们,例如使用示例中的循环或写入另一个通道。当你知道你已经处理完所有内容时,你可以使用 clear
将缓冲区设置为初始状态,可以从头到尾填充它。
否则,如果它可能包含未处理的数据,请改用compact
,这会将未处理的数据移动到缓冲区的开头并准备接收更多数据after[=45] =] 它们,因此在随后的 read
和 flip
之后,您将拥有前一次迭代的未决数据,然后是最新读取操作的数据,准备作为单个序列进行处理。 (这就是 Reader
在解码时内部处理不完整字符序列的方式)
最近我开始学习java.nio。我在教科书中有一个例子,如何使用 SeekableByteChannel:
读取文本文件int count;
Path path;
try {
path = Paths.get(System.getProperty("user.home") + "/desktop/text.txt");
} catch (InvalidPathException e) {
out.println(e.getMessage());
return;
}
try (SeekableByteChannel channel = Files.newByteChannel(path)) {
ByteBuffer buffer = ByteBuffer.allocate(128);
do {
count = channel.read(buffer);
if (count != -1) {
buffer.rewind();
for (int i = 0; i < count; i++)
out.print((char) buffer.get());
}
} while (count != -1);
} catch (IOException e) {
out.println("File not found!!!");
}
out.flush();
所以我使用 ANSI 编码制作了一个包含英语和俄语单词的文本文件。这就是我得到的:
方法buffer.get()returnsbyte值和俄文字符从1000开始。所以我已将编码更改为 UTF-8 并使用另一种方法:
for (int i = 0; i < count; i += 2)
out.print(buffer.getChar()); //reads 2 bytes and converts them to char
但这给了我一行问号。
那么有人知道如何使用 SeekableByteChannel 正确阅读俄语文本吗?
ByteBuffer
的方法getChar()
读取两个字节,并解释为char
的高字节和低字节,也就是说,总是使用UTF-16
编码。一般来说,你不应该尝试手动将字节拼凑成 String
s,旧的 I/O API 和 NIO 都不行。仅提及在尝试手动解码缓冲区中的字节时必须处理的一件事,即缓冲区中的字节可能不会在多字节编码的字符边界处结束。
如果您想从 SeekableByteChannel
中读取文本,您可以使用 Channels.newReader(…)
构造一个 Reader
使用指定的字符集来解码字节。
但是,当然,您可以完全跳过 Channel
内容并使用 Files.newBufferedReader(…)
从 Path
.
Reader
顺便说一句,示例代码是有问题的,即使是读取字节序列也是如此。这是一个简化的例子:
Path path=Paths.get(System.getProperty("user.home")).resolve("desktop/text.txt");
try(FileChannel channel=FileChannel.open(path)) {
ByteBuffer buffer = ByteBuffer.allocate(128);
while(channel.read(buffer)!=-1) {
buffer.flip();
while(buffer.hasRemaining())
System.out.printf("%02x ", buffer.get());
buffer.clear();
System.out.println();
}
} catch (IOException e) {
System.out.println(e.toString());
}
A ByteBuffer
知道它包含多少字节(即已通过读取操作放入其中)。使用 flip
可以准备缓冲区以读出它们,例如使用示例中的循环或写入另一个通道。当你知道你已经处理完所有内容时,你可以使用 clear
将缓冲区设置为初始状态,可以从头到尾填充它。
否则,如果它可能包含未处理的数据,请改用compact
,这会将未处理的数据移动到缓冲区的开头并准备接收更多数据after[=45] =] 它们,因此在随后的 read
和 flip
之后,您将拥有前一次迭代的未决数据,然后是最新读取操作的数据,准备作为单个序列进行处理。 (这就是 Reader
在解码时内部处理不完整字符序列的方式)