我需要从文件中读取文本,例如在控制台中打印它。该文件采用 UTF-8 格式。看来我做错了什么,因为一些俄语符号打印不正确。我的代码有什么问题吗?
StringBuilder content = new StringBuilder();
try (FileChannel fChan = (FileChannel) Files.newByteChannel(Paths.get("D:/test.txt")) ) {
ByteBuffer byteBuf = ByteBuffer.allocate(16);
Charset charset = Charset.forName("UTF-8");
while(fChan.read(byteBuf) != -1) {
byteBuf.flip();
content.append(new String(byteBuf.array(), charset));
byteBuf.clear();
}
System.out.println(content);
}
结果:
Здравствуйте, как поживае��е?
Это п��имер текста на русском яз��ке.ом яз�
实际文本:
Здравствуйте, как поживаете?
Это пример текста на русском языке.
最佳答案
UTF-8 每个字符使用可变的字节数。这会给你带来一个边界错误:你将基于缓冲区的代码与基于字节数组的代码混合在一起,并且你不能在这里这样做;您可能会读取足够多的字节来卡在一个字符中,然后将输入转换为字节数组并进行转换,这会失败,因为您无法转换半个字符。
您真正想要的是首先读取所有数据,然后转换整个输入,或者,当您翻转时将任何半字符保留在字节缓冲区中,或者更好的是,放弃所有这些内容并使用以下代码被写入以读取实际字符。一般来说,使用 channel API 会使事情变得非常复杂;它很灵活,但很复杂 - 就是这样。
除非您能解释为什么需要它,否则不要使用它。改为这样做:
Path target = Paths.get("D:/test.txt");
try (var reader = Files.newBufferedReader(target)) {
// read a line at a time here. Yes, it will be UTF-8 decoded.
}
或者更好,因为你显然想一口气读完整本书:
Path target = Paths.get("D:/test.txt");
var content = Files.readString(target);
注意:与大多数将字节转换为字符或反之亦然的 java 方法不同,Files
API 默认为 UTF-8(而不是无用且危险、无法测试错误的“平台默认编码”) ' 大多数 java API 都是这样做的)。这就是为什么这最后一个极其简单的代码仍然是正确的。
关于java - Java NIO 解码过程中如何去掉不正确的符号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64728361/