【问题标题】:Why don't DataOutputStream.writeChars(str) and String(byte[]) use the same encoding?为什么 DataOutputStream.writeChars(str) 和 String(byte[]) 不使用相同的编码?
【发布时间】:2013-02-02 08:46:05
【问题描述】:

我正在为一个类项目编写一些编组/解组例程,并且对 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-16 中都以 0 字节开头,因此构造函数似乎只是放弃了返回一个空字符串。解决办法是改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[]) 构造函数的默认行为不相互平行?

【问题讨论】:

  • 使用DataOutputStream.writeUTF()DataInputStream.readUTF()怎么样?
  • ....哇,这样方便多了。谢谢你。我仍然很好奇为什么我的方法没有按预期工作,但我想我会改用这些方法。
  • 我发布了一个完整的解释,希望能解决问题。

标签: java string character-encoding marshalling unmarshalling


【解决方案1】:

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

【讨论】:

  • String(byte[])构造函数不一定使用UTF-8,而是平台默认编码。
【解决方案2】:

最好认为 Java 不对其字符使用任何编码。它的字符串只是原始的 16 位字符值,与 UTF16 相同。 “其他”方法默认使用系统编码的原因是因为不同的平台使用不同的默认编码。例如,将包含部分 ascii 字符的 UTF8 写入使用 EBDCDIC (sp) 的大型机是没有意义的。

【讨论】:

    猜你喜欢
    • 2022-09-26
    • 2012-11-14
    • 2011-06-25
    • 2017-11-21
    • 2019-09-22
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多