2012-11-26 31 views
10

我需要將對象序列化爲字符串並反序列化。如何二進制(德)序列化對象到/表單字符串?

我readed sugestion計算器上,讓這樣的代碼:

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());,由於字符串轉換破壞的數據(因爲編碼的)。

如果您確實需要將結果存儲在字符串中,則需要一種安全的方式將任意字節存儲在字符串中。這樣做的一個方法是我們Base64編碼。

完全不同的方法是不使用此類的標準Java序列化,而是創建自己的數據到字符串轉換器。

+1

+1不要忘記關閉流以及它的緩衝區。 ;) –

+2

Base64減緩了這個問題。 :) – LunaVulpo

+0

謝謝,我應該知道這是一個編碼問題。在我的情況下,我需要使用org.apache.tomcat.util.codec.binary.Base64與Base64.encodeBase64String來創建字符串和Base64.decodeBase64來解碼它。 –

11

說轉換爲字符串會破壞數據並不完全正確。轉換爲「UTF-8」是因爲它不是雙射的(有些字符是2字節,但並非所有的2字節序列都允許作爲字符序列),而「ISO-8859-1」是雙射字符(字符串的1個字符是字節,反之亦然)。

與此相比,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。 –

相關問題