java - 为什么 DataOutputStream.writeChars(str) 和 String(byte[]) 不使用相同的编码?

标签 java string character-encoding marshalling unmarshalling

我正在为一个类项目编写一些编码/解码例程,我对 Java 在这种情况下的默认行为有点困惑。这是我的“天真”子程序,用于在字节流中写入和读取字符串:

protected static void write(DataOutputStream dout, String str)
        throws IOException{
    dout.writeInt(str.length());
    dout.writeChars(str);
}

protected static String readString(DataInputStream din)
        throws IOException{
    int strLength = 2*din.readInt(); // b/c there are two bytes per char
    byte[] stringHolder = new byte[strLength];
    din.read(stringHolder);
    return new String(stringHolder);
}

不幸的是,这根本行不通;默认情况下,字符以 UTF-16 格式编写,但 String(byte[]) 似乎假定每个字节都包含一个字符,并且由于 ASCII 字符在 UTF 中都以 0 字节开头- 16、构造函数似乎只是放弃并返回一个空字符串。解决方法是将readString改成必须使用UTF-16编码:

protected static String readString(DataInputStream din)
        throws IOException{
    int strLength = 2*din.readInt();
    byte[] stringHolder = new byte[strLength];
    din.read(stringHolder);
    return new String(stringHolder, "UTF-16");
}

我的问题是,为什么这是必要的?由于 Java 默认对字符串使用 UTF-16,为什么它不假设在从字节读取字符时使用 UTF-16?或者,为什么默认情况下它不首先将字符编码为字节?简而言之,为什么 writeChars() 方法和 String(byte[]) 构造函数的默认行为彼此不平行?

最佳答案

问题是您正在使用底层 char[] 进行编写,它本质上是一个 byte[] 表示字符串的 UTF-16 表示形式,请参阅 javadoc .
然后,您将使用 String(byte[] bytes) 构造函数进行读取,该构造函数旨在读取使用系统默认编码编码的数据,在您的情况下可能是 UTF-8。
您需要保持一致,事实上 DataOutputStream.writeUTF()DataInputStream.readUTF() 函数是专门为此设计的。
如果出于某种原因你想使用底层的 byte[] 你可以使用 String.getBytes("UTF-8 "),再次查看 javadoc
为了简化问题,您可以只使用 ObjectOutputStreamObjectInputStream 并将实际的 String 序列化为流,而不仅仅是它的 char[] 表示。

关于java - 为什么 DataOutputStream.writeChars(str) 和 String(byte[]) 不使用相同的编码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14927521/

相关文章:

java - 当从用户那里获取名称输入时,如何让它在重新启动时保留在 Activity 中?

java - 从图片回调中读取 android jpeg EXIF 元数据

java - 在 Java 中为 JTextField 显示事件?

c++ - std::cin 输入带空格?

http - tomcat的字符编码问题

java - 将默认字符集更改为 UTF-8

java - itext7 pdf 与书签合并

regex - 两个字符串之间的精确匹配 - 线性编辑距离?

c++ - 二进制模式下的 std::ifstream 和 C++ 中的区域设置

windows - 检测 C/C++ 中字符串的编码