2012-11-26 2 views
10

Ich muss Objekte in String serialisieren und deserialisieren.Wie binäre (de) serialisieren Objekt in/Form String?

I readed sugestion auf Stackoverflow und diesen Code machen:

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(); 
    } 

} 

}

aber ich Fehler:

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) 

Warum? ich erwartet: d.x = 5 d.y = 3

wie in guter weise zu tun? Ah. Ich möchte dieses Objekt nicht in eine Datei schreiben. Ich muss es im String-Format haben.

+1

Warum genau haben Sie eine binäre Darstellung in einem String in erster Linie speichern? Warum nicht einfach als Byte-Array oder etwas? –

+0

@CostiCiudatu beacuse Ich muss eine Methode schreiben, die Objekte in SQLite-Datenbank speichern, aber Teil in SQLite ist nicht von mir abhängig. Und es gibt eine Textspalte. Jetzt habe ich XML-Serialisierung, aber es ist langsam. Ich brauche schnellen Weg. – LunaVulpo

+0

Haben Sie überprüft, ob SQLite so etwas wie BLOB zum Speichern von Rohbytes unterstützt? –

Antwort

10

Verwenden
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); anstelle von ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());, da der String Umwandlung der Daten (wegen der Codierung) korrumpiert.

Wenn Sie das Ergebnis wirklich in einem String speichern müssen, benötigen Sie eine sichere Möglichkeit, beliebige Bytes in einem String zu speichern. Eine Möglichkeit dazu ist die Base64-Codierung.

Ein völlig anderer Ansatz wäre gewesen, die Standard-Java-Serialisierung für diese Klasse nicht zu verwenden, sondern einen eigenen Data to/from String-Konverter zu erstellen.

+1

+1 vergessen Sie nicht, den Stream sowie seine gepufferte zu schließen. ;) –

+2

Base64 verlangsamt dieses Problem. :) – LunaVulpo

+0

Danke, ich hätte wissen müssen, dass es sich um ein Kodierungsproblem handelt. In meinem Fall musste ich org.apache.tomcat.util.codec.binary.Base64 mit Base64.encodeBase64String zum Erstellen der Zeichenfolge und Base64.decodeBase64 zum Entschlüsseln verwenden. –

11

Es ist nicht ganz richtig zu sagen, dass die Umwandlung in Zeichenfolge die Daten korrumpiert. Die Konvertierung in "UTF-8" funktioniert, weil sie nicht bijektiv ist (einige Zeichen sind 2 Bytes, aber nicht alle 2 Bytes sind als Zeichenfolgen erlaubt), während "ISO-8859-1" bijektiv ist (1 Zeichen eines Strings ist a Byte und umgekehrt).

Die Base64-Codierung ist im Vergleich dazu nicht sehr platzsparend.

Aus diesem Grunde würde ich empfehlen:

/** 
* 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

Wie können Sie sicher sein, dass die Binärdarstellung in 'String' konvertiert werden kann? Zum Beispiel, wie kann das 'String'-Terminatorzeichen (normalerweise' \ 0' in C) in ein gültiges Zeichen ** innerhalb der 'String' umgewandelt werden? Die Antwort ist, du kannst nicht. Aus diesem Grund sollten wir das Byte-Array in eine sichere Textdarstellung wie Base64 konvertieren. –

Verwandte Themen