2012-11-26 11 views
10

Potrzebuję serializować obiekty w łańcuchu i deserializować.W jaki sposób binarny (de) serializuje obiekt do ciągu/formularza?

I odczytany sugestii na stackoverflow i uczynić ten kod:

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

} 

}

ale dostaję błąd:

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) 

Dlaczego? Spodziewałem: d.x = 5 d.y = 3

jak to zrobić w dobrym kierunku? Ah. Nie chcę zapisywać tego obiektu w pliku. Muszę to mieć w formacie smyczkowym.

+1

Dlaczego dokładnie chcesz zapisać reprezentację binarną w ciągu w pierwszej kolejności? Dlaczego nie po prostu zachować go jako tablicy bajtowej czy coś takiego? ... –

+0

@CostiCiudatu beacuse Muszę napisać metodę, która przechowuje obiekty do bazy danych sqlite, ale część w sqlite nie jest zależna ode mnie. I jest kolumna tekstowa. Teraz mam serializację xml, ale jest wolna. Potrzebuję szybkiej drogi. – LunaVulpo

+0

Czy sprawdziłeś, czy SQLite obsługuje coś w rodzaju BLOBa do przechowywania surowych bajtów? –

Odpowiedz

10

Zastosowanie
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); zamiast ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());, ponieważ psuje konwersji ciąg danych (z powodu kodowania).

Jeśli naprawdę potrzebujesz zapisać wynik w łańcuchu, potrzebujesz bezpiecznego sposobu przechowywania dowolnych bajtów w łańcuchu. Jednym ze sposobów robienia tego jest dla nas kodowanie Base64.

Całkowicie odmienne podejście polegałoby na tym, aby nie używać standardowej serializacji Java dla tej klasy, ale utworzyć własny konwerter danych do/z String.

+1

+1 nie zapomnij zamknąć strumienia, a także jego buforowanie. ;) –

+2

Base64 spowolnił ten problem. :) – LunaVulpo

+0

Dzięki, powinienem był wiedzieć, że to był problem z kodowaniem. W moim przypadku potrzebowałem użyć org.apache.tomcat.util.codec.binary.Base64 z Base64.encodeBase64String, aby utworzyć ciąg i Base64.decodeBase64, aby go zdekodować. –

11

To nie do końca prawda, że ​​konwersja na ciąg powoduje uszkodzenie danych. Konwersja do "UTF-8" polega na tym, że nie jest bijective (niektóre znaki mają 2 bajty, ale nie wszystkie 2 bajty sekwencji są dozwolone jako sekwencje znaków), podczas gdy "ISO-8859-1" jest bijective (1 znak ciągu jest bajt i odwrotnie).

Kodowanie Base64 nie zajmuje zbyt dużo miejsca w porównaniu do tego.

Dlatego polecam:

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

Jak możesz być pewien, że reprezentacja binarna może zostać przekonwertowana na 'String'? Na przykład, jak można przekształcić znak kończący 'String' (zwykle' \ 0' w C) na poprawny znak ** wewnątrz ** 'String'? Odpowiedź brzmi: nie możesz. Z tego powodu powinniśmy przekonwertować tablicę bajtów na bezpieczną reprezentację tekstową, taką jak Base64. –

Powiązane problemy