1

私はクラスプロジェクトのマーシャリング/アンマーシャリングルーチンをいくつか書いていますが、この場合の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[])各バイトに文字が含まれると想定しているようです。また、UTF-16ではASCII文字はすべて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[])コンストラクターのデフォルトの動作が互いに並行していないのはなぜですか?

4

2 に答える 2

4

問題は、文字列のUTF-16表現を表すchar[]基本的なaを使用して記述していることです。javadocを参照してください。 次に、システムのデフォルトのエンコードでエンコードされたデータを読み取るために設計されたコンストラクターを使用して読み取ります。この場合、おそらくこれはUTF-8です。 一貫性を保つ必要があります。実際、および関数はこのために特別に設計されています。何らかの理由で基に なるものを使用したい場合は、簡単に使用できるUTF-8表現を取得できます。これもjavadocを参照してください。 問題を単純化するために、とを使用するだけで、実際のシリアル化が可能になりますbyte[]
String(byte[] bytes)
DataOutputStream.writeUTF()DataInputStream.readUTF()
byte[]StringString.getBytes("UTF-8")
ObjectOutputStreamObjectInputStreamStringchar[]単なる表現ではなく、ストリームに。

于 2013-02-18T00:11:29.523 に答える
0

Javaはその文字のエンコーディングを使用しないと考える方がよいでしょう。その文字列は、UTF16と同じ生の16ビット文字値です。「その他」のメソッドがデフォルトでシステムエンコーディングになっている理由は、プラットフォームごとに異なるデフォルトエンコーディングが使用されているためです。たとえば、部分的なASCII文字を含むUTF8を、EBDCDIC(sp)を使用するメインフレームに書き込むことは意味がありません。

于 2013-02-18T02:25:05.933 に答える