Java Nio ByteBuffer 在缓冲区达到其边界时截断 unicode 字符
Java Nio ByteBuffer truncate unicode characters when buffer reaches its bound
我在 java 中编写了一个函数,它可以读取文件并将其内容获取到字符串:
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,但是对于非常大的文本文件来说并不实用。
问题
如何解决这个问题?
你不能,因为你不知道 UTF-8 编码中每个字符使用了多少字节,你真的不想重写那个逻辑。
有Files.readString() in Java 11, for lower versions you can use Files.readAllBytes()例如
Path path = new File(fileLocation).toPath()
String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
我在 java 中编写了一个函数,它可以读取文件并将其内容获取到字符串:
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,但是对于非常大的文本文件来说并不实用。
问题
如何解决这个问题?
你不能,因为你不知道 UTF-8 编码中每个字符使用了多少字节,你真的不想重写那个逻辑。
有Files.readString() in Java 11, for lower versions you can use Files.readAllBytes()例如
Path path = new File(fileLocation).toPath()
String contents = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);