Java Nio ByteBuffer 在缓冲区达到其边界时截断 Unicode 字符

Java Nio ByteBuffer truncate unicode characters when buffer reaches its bound

提问人:Paper_Folding 提问时间:8/19/2021 最后编辑:Paper_Folding 更新时间:8/19/2021 访问量:395

问:

我正在用 java 编写一个函数,该函数可以读取文件并将其内容转换为 String:

public static String ReadFromFile(String fileLocation) {
    StringBuilder result = new StringBuilder();
    RandomAccessFile randomAccessFile = null;
    FileChannel fileChannel = null;
    try {
        randomAccessFile = new RandomAccessFile(fileLocation, "r");
        fileChannel = randomAccessFile.getChannel();
        ByteBuffer byteBuffer = ByteBuffer.allocate(10);
        CharBuffer charBuffer = null;
        int bytesRead = fileChannel.read(byteBuffer);
        while (bytesRead != -1) {
            byteBuffer.flip();
            charBuffer = StandardCharsets.UTF_8.decode(byteBuffer);
            result.append(charBuffer.toString());
            byteBuffer.clear();
            bytesRead = fileChannel.read(byteBuffer);
        }
    } catch (IOException ignored) {
    } finally {
        try {
            if (fileChannel != null)
                fileChannel.close();
            if (randomAccessFile != null)
                randomAccessFile.close();
        } catch (IOException ignored) {
        }
    }
    return result.toString();
}

从上面的代码中,您可以看到我故意将“ByteBuffer.allocate”设置为仅 10 个字节,以使事情更清晰。 现在我想读取一个名为“test.txt”的文件,其中包含中文的 unicode 字符,如下所示:

乐正绫我爱你乐正绫我爱你

以下是我的测试代码:

System.out.println(ReadFromFile("test.txt"));

控制台中的预期输出

乐正绫我爱你乐正绫我爱你

控制台中的实际输出

乐正绫���爱你��正绫我爱你

可能的原因
ByteBuffer 只分配了 10 个字节,因此 unicode 字符每 10 个字节被截断一次。

尝试解决
将 ByteBuffer 分配的字节增加到 20,我得到了以下结果:

乐正绫我爱你��正绫我爱你

不是一个强大的解决方案
将 ByteBuffer 分配给一个非常大的数字,比如 102400,但当涉及到非常大的文本文件时,这是不切实际的。

问:
如何解决这个问题?

Java Unicode IO NIO 文件阅读器

评论

1赞 Joachim Sauer 8/19/2021
你正在使这种方式变得复杂。即使您不知道答案指出的方法,您也应该使用正确的编码打开一个并使用 .所有这些额外的复杂性并不能真正给你带来什么好处。或者换个说法:你认为为什么你需要蔚来汽车?FileReaderread
0赞 skomisa 8/19/2021
您是否有理由特别想要/需要与蔚来一起这样做,或者您只是出于好奇而提出一个假设性的问题,在这种情况下,您的问题可以说是偏离主题的,因此可能会被关闭。
0赞 Paper_Folding 8/19/2021
我明白了,蔚来不是必须的。如果问题可以解决,无论使用什么方法都没关系。

答:

2赞 Kayaman 8/19/2021 #1

你不能,因为你不知道 UTF-8 编码中每个字符使用了多少个字节,而且你真的不想重写这个逻辑。

Java 11 中有 Files.readString(),对于较低版本,您可以使用 Files.readAllBytes(),例如

Path path = new File(fileLocation).toPath()
String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);

评论

0赞 Joachim Sauer 8/19/2021
我试图弄清楚如何在这里正确使用 CharsetDecoder.decodeLoop,直到我意识到 OP 只是编写了一种非常复杂的方法来读取整个文件内容作为......String
0赞 Paper_Folding 8/19/2021
嘿,我想知道是否有任何类似的方法可以编写 String 来如此轻松地提交文件,因为我也编写了一个非常复杂的 WriteStringToFile 方法。
0赞 user207421 8/19/2021
@Paper_Folding .java.net.FileWriter
0赞 Paper_Folding 8/19/2021
@user207421 解决方式java.nio.file.Files.writeString