2012-11-26 6 views
10

オブジェクトをシリアル化してStringに変換し、逆シリアル化する必要があります。オブジェクトを/フォーム文字列にバイナリ(de)シリアル化する方法は?

私はStackOverflowの上で暗示をreadedこのコードます

class Data implements Serializable { 
int x = 5; 
int y = 3; 
} 

public class Test { 
public static void main(String[] args) { 

    Data data = new Data(); 

    String out; 

    try { 
     // zapis 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 

     oos.writeObject(data); 

     out = new String(baos.toByteArray()); 
     System.out.println(out); 

     // odczyt.========================================== 

     ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes()); 

     ObjectInputStream ois = new ObjectInputStream(bais); 

     Data d = (Data) ois.readObject(); 

     System.out.println("d.x = " + d.x); 
     System.out.println("d.y = " + d.y); 

    } catch (FileNotFoundException e) { 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } catch (ClassNotFoundException e) { 
     e.printStackTrace(); 
    } 

} 

}

を私はエラーを取得:

java.io.StreamCorruptedException: invalid stream header: EFBFBDEF 
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:801) 
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:298) 
at p.Test.main(Test.java:37) 

なぜ? は私が予想: d.x = 5 d.y = 3

どのように良い方法で行うには? ああ。私はこのオブジェクトをファイルに書きたくありません。私は文字列形式でそれを持っている必要があります。

+1

を正確にあなたが最初の場所で文字列内のバイナリ表現を格納したいのはなぜ?私はバイト配列や何かとして保持していないのですか?... –

+0

@CostiCiudatu beacuse sqliteデータベースにオブジェクトを格納するメソッドを書く必要がありますが、sqliteの一部は私に依存しません。そして、テキストの列があります。今私はxmlのシリアル化がありますが、それは遅いです。私は速い道が必要です。 – LunaVulpo

+0

SQLiteが生のバイトを格納するBLOBのようなものをサポートしているかどうかチェックしましたか? –

答えて

10

使用
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());代わりに ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());、文字列の変換は(理由符号化の)データを破壊するからです。

実際に結果をStringに格納する必要がある場合は、任意のバイトをStringに格納する安全な方法が必要です。これを行うための1つの方法は、Base64エンコーディングです。

全く異なるアプローチは、このクラスに標準のJavaシリアル化を使用せず、独自のData to String変換を作成することでした。

+1

+1ストリームとバッファされたストリームを閉じるのを忘れないでください。 ;) –

+2

Base64でこの問題が緩和されました。 :) – LunaVulpo

+0

ありがとう、私はこれがエンコーディングの問題であることがわかったはずです。私の場合は、org.apache.tomcat.util.codec.binary.Base64とBase64.encodeBase64Stringを使用して文字列を作成し、Base64.decodeBase64をデコードする必要がありました。 –

11

文字列への変換によってデータが破損するとは言いません。 「ISO-8859-1」は全単射(文字列の1文字はaであるが、全文字列は2バイトであるが、すべての2バイトシーケンスが文字シーケンスとして許されるわけではない)であるため、「UTF-8」への変換は全単射ではないバイト、またはその逆)。

Base64エンコーディングは、これに比べてスペース効率があまり高くありません。

私がお勧めする理由はここにある:

/** 
* Serialize any object 
* @param obj 
* @return 
*/ 
public static String serialize(Object obj) { 
    try { 
     ByteArrayOutputStream bo = new ByteArrayOutputStream(); 
     ObjectOutputStream so = new ObjectOutputStream(bo); 
     so.writeObject(obj); 
     so.flush(); 
     // This encoding induces a bijection between byte[] and String (unlike UTF-8) 
     return bo.toString("ISO-8859-1"); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
/** 
* Deserialize any object 
* @param str 
* @param cls 
* @return 
*/ 
public static <T> T deserialize(String str, Class<T> cls) { 
    // deserialize the object 
    try { 
     // This encoding induces a bijection between byte[] and String (unlike UTF-8) 
     byte b[] = str.getBytes("ISO-8859-1"); 
     ByteArrayInputStream bi = new ByteArrayInputStream(b); 
     ObjectInputStream si = new ObjectInputStream(bi); 
     return cls.cast(si.readObject()); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
} 
+0

バイナリ表現を 'String'に変換できることをどのように確認できますか?例えば、 'String'ターミネーター文字(通常は' C \で '\ 0 ')を' String'内の有効な文字**に変換できますか?答えは、あなたはできません。そのため、バイト配列をBase64などの安全なテキスト表現に変換する必要があります。 –

関連する問題