2012-11-26 16 views
10

Ho bisogno di serializzare oggetti in String e deserializzare.Come eseguire il binario (de) serializzare l'oggetto in/form string?

ho readed sugestion su StackOverflow e rendere questo codice:

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

} 

}

ma ottengo l'errore:

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) 

Perché? Mi aspettavo: d.x = 5 d.y = 3

come fare in modo corretto? Ah. Non voglio scrivere questo oggetto nel file. Devo averlo in formato stringa.

+1

Perché proprio vuoi archiviare una rappresentazione binaria in una stringa, in primo luogo? Perché non tenerlo semplicemente come un array di byte o qualcosa del genere? ... –

+0

@CostiCiudatu perché devo scrivere un metodo che memorizza gli oggetti nel database sqlite ma una parte in sqlite non dipende da me. E c'è una colonna di testo. Ora ho serializzazione xml ma è lento. Ho bisogno di un modo veloce. – LunaVulpo

+0

Hai verificato se SQLite supporta qualcosa come BLOB per la memorizzazione di byte non elaborati? –

risposta

10

Uso
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); anziché ByteArrayInputStream bais = new ByteArrayInputStream(out.getBytes());, poiché la conversione String danneggia i dati (a causa della codifica).

Se è davvero necessario archiviare il risultato in una stringa, è necessario un modo sicuro per archiviare byte arbitrari in una stringa. Un modo per farlo è per noi codifica Base64.

Un approccio completamente diverso sarebbe stato quello di non utilizzare la serializzazione Java standard per questa classe, ma creare i propri dati da/per convertitore di stringhe.

+1

+1 non dimenticare di chiudere lo stream e il relativo buffer. ;) –

+2

Base64 ha rallentato questo problema. :) – LunaVulpo

+0

Grazie, avrei dovuto sapere che si trattava di un problema di codifica. Nel mio caso avevo bisogno di usare org.apache.tomcat.util.codec.binary.Base64 con Base64.encodeBase64String per creare la stringa e Base64.decodeBase64 per decodificarlo. –

11

Non è del tutto vero dire che la conversione in stringa danneggia i dati. La conversione in "UTF-8" avviene perché non è bijective (alcuni caratteri sono 2 byte ma non tutte le sequenze di 2 byte sono consentite come sequenze di caratteri), mentre "ISO-8859-1" è bijective (1 carattere di una stringa è un byte e viceversa).

La codifica Base64 non è molto efficiente in termini di spazio rispetto a questa.

Per questo mi sento di raccomandare:

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

Come si può essere sicuri che la rappresentazione binaria possa essere convertita in 'String'? Per esempio, come può il carattere terminatore 'String' (di solito' \ 0' in C) essere convertito in un carattere valido ** dentro ** the 'String'? La risposta è, non puoi. Per questo motivo dovremmo convertire l'array di byte in una rappresentazione testuale sicura, come Base64. –

Problemi correlati