2008-09-25 59 views
126

我可以將對象序列化爲文件,然後再次將其恢復,如下面的代碼片段所示。我想將該對象序列化爲一個字符串,並將其存儲到數據庫中。誰能幫我?如何將對象序列化爲字符串

LinkedList<Diff_match_patch.Patch> patches = // whatever... 
FileOutputStream fileStream = new FileOutputStream("foo.ser"); 
ObjectOutputStream os = new ObjectOutputStream(fileStream); 
os.writeObject(patches1); 
os.close(); 

FileInputStream fileInputStream = new FileInputStream("foo.ser"); 
ObjectInputStream oInputStream = new ObjectInputStream(fileInputStream); 
Object one = oInputStream.readObject(); 
LinkedList<Diff_match_patch.Patch> patches3 = (LinkedList<Diff_match_patch.Patch>) one; 
os.close(); 

回答

242

塞爾吉奧:

您應該使用BLOB。這與JDBC非常相似。

您發佈的第二個代碼的問題是編碼。您應該額外編碼字節以確保它們都不會失敗。

如果您仍想將其寫入字符串中,則可以使用java.util.Base64對字節進行編碼。

仍然應該使用CLOB作爲數據類型,因爲您不知道序列化數據將要運行多長時間。

下面是如何使用它的示例。

import java.util.*; 
import java.io.*; 

/** 
* Usage sample serializing SomeClass instance 
*/ 
public class ToStringSample { 

    public static void main(String [] args) throws IOException, 
                 ClassNotFoundException { 
     String string = toString(new SomeClass()); 
     System.out.println(" Encoded serialized version "); 
     System.out.println(string); 
     SomeClass some = (SomeClass) fromString(string); 
     System.out.println("\n\nReconstituted object"); 
     System.out.println(some); 


    } 

    /** Read the object from Base64 string. */ 
    private static Object fromString(String s) throws IOException , 
                 ClassNotFoundException { 
     byte [] data = Base64.getDecoder().decode(s); 
     ObjectInputStream ois = new ObjectInputStream( 
             new ByteArrayInputStream( data)); 
     Object o = ois.readObject(); 
     ois.close(); 
     return o; 
    } 

    /** Write the object to a Base64 string. */ 
    private static String toString(Serializable o) throws IOException { 
     ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos); 
     oos.writeObject(o); 
     oos.close(); 
     return Base64.getEncoder().encodeToString(baos.toByteArray()); 
    } 
} 

/** Test subject. A very simple class. */ 
class SomeClass implements Serializable { 

    private final static long serialVersionUID = 1; // See Nick's comment below 

    int i = Integer.MAX_VALUE; 
    String s = "ABCDEFGHIJKLMNOP"; 
    Double d = new Double(-1.0); 
    public String toString(){ 
     return "SomeClass instance says: Don't worry, " 
       + "I'm healthy. Look, my data is i = " + i 
       + ", s = " + s + ", d = " + d; 
    } 
} 

輸出:

C:\samples>javac *.java 

C:\samples>java ToStringSample 
Encoded serialized version 
rO0ABXNyAAlTb21lQ2xhc3MAAAAAAAAAAQIAA0kAAWlMAAFkdAASTGphdmEvbGFuZy9Eb3VibGU7T 
AABc3QAEkxqYXZhL2xhbmcvU3RyaW5nO3hwf////3NyABBqYXZhLmxhbmcuRG91YmxlgLPCSilr+w 
QCAAFEAAV2YWx1ZXhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cL/wAAAAAAAAdAAQQUJ 
DREVGR0hJSktMTU5PUA== 


Reconstituted object 
SomeClass instance says: Don't worry, I'm healthy. Look, my data is i = 2147483647, s = ABCDEFGHIJKLMNOP, d = -1.0 

注意:對Java 7及更早版本,你可以看到原來的answer here

11

如何將數據寫入ByteArrayOutputStream而不是FileOutputStream?否則,您可以使用XMLEncoder序列化對象,保留XML,然後通過XMLDecoder反序列化。

0

可以使用UUEncoding

3

如果你存儲的對象在數據庫中的二進制數據,那麼你真的應該使用BLOB數據類型。數據庫能夠更高效地存儲它,並且不必擔心編碼等問題。 JDBC提供了用於根據流創建和檢索blob的方法。如果可以的話,使用Java 6,它增加了一些JDBC API,使處理blob變得更容易。

如果你絕對需要的數據存儲爲一個字符串,我會建議XStream基於XML的存儲(比XMLEncoder容易得多),但替代對象表示可能是一樣有用(例如JSON)。你的方法取決於你爲什麼需要以這種方式存儲對象。

1

串行化流只是一個字節序列(八位字節)。所以問題是如何將字節序列轉換爲字符串,然後再返回。此外,如果將要存儲在數據庫中,則需要使用有限的一組字符代碼。

問題的明顯解決方案是將字段更改爲二進制LOB。如果你想堅持一個字符集LOB,那麼你需要編碼一些方案,如base64,hex或uu。

7

感謝您的回覆。我會立即給出一些贊成票來表示你的幫助。根據您的回答,我已經根據我的觀點編寫了最佳解決方案。

LinkedList<Patch> patches1 = diff.patch_make(text2, text1); 
try { 
    ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
    ObjectOutputStream os = new ObjectOutputStream(bos); 
    os.writeObject(patches1); 
    String serialized_patches1 = bos.toString(); 
    os.close(); 


    ByteArrayInputStream bis = new ByteArrayInputStream(serialized_patches1.getBytes()); 
    ObjectInputStream oInputStream = new ObjectInputStream(bis); 
    LinkedList<Patch> restored_patches1 = (LinkedList<Patch>) oInputStream.readObject();    



     // patches1 equals restored_patches1 
    oInputStream.close(); 
} catch(Exception ex) { 
    ex.printStackTrace(); 
} 

注意我沒有使用JSON,因爲是低效率的考慮。

注意:我會考慮您的建議,不要將序列化對象作爲字符串存儲在數據庫中,而是存儲在byte []中。

+3

「ByteArrayOutputStream.toString使用*平臺默認的編碼轉換*。您確定要嗎?尤其是作爲一個任意字節數組是無效的UTF8。此外,數據庫將打亂它。「 – 2008-09-25 17:57:44

+0

您應該認真對待Tom Hawtin的上述評論 – anjanb 2008-09-25 18:12:00

1

看看在java.sql.PreparedStatement中的類,具體功能

http://java.sun.com/javase/6/docs/api/java/sql/PreparedStatement.html#setBinaryStream(int,%20java.io.InputStream)

然後看看是java.sql.ResultSet類,具體功能

http://java.sun.com/javase/6/docs/api/java/sql/ResultSet.html#getBinaryStream(int)

請記住,如果你是一個序列化對象到數據庫,然後更改對象在你的代碼在新版本中,反序列化過程很容易失敗,因爲對象的簽名已更改。我曾經犯過一個錯誤,那就是存儲一個自定義的首選項,然後對首選項定義進行更改。突然之間,我無法讀取任何以前的序列化信息。

您最好在表中編寫笨笨的每個屬性列,並以這種方式組合和分解對象,以避免對象版本和反序列化造成這個問題。或者將屬性寫入某種類的散列映射(如java.util.Properties對象),然後序列化非常不可能改變的屬性對象。

1

可以使用sun.misc.Base64Decoder和sun.misc.Base64Encoder類中的構建將serialize的二進制數據轉換爲字符串。你不需要額外的類,因爲它是內置的。

4

XStream提供了一個簡單的實用程序,用於從XML序列化/反序列化,它的很快。存儲XML CLOB而不是二進制BLOBS將不那麼脆弱,更不用說更具可讀性了。

0

Java8方法,將Object從/轉換爲String,靈感來自於OscarRyz的回答。對於解碼/編碼,需要使用java.util.Base64

import java.io.ByteArrayInputStream; 
import java.io.ByteArrayOutputStream; 
import java.io.IOException; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.io.Serializable; 
import java.util.Base64; 
import java.util.Optional; 

interface ObjectHelper { 

    static Optional<String> convertToString(final Serializable object) { 
    try (final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
     ObjectOutputStream oos = new ObjectOutputStream(baos)) { 
     oos.writeObject(object); 
     return Optional.of(Base64.getEncoder().encodeToString(baos.toByteArray())); 
    } catch (final IOException e) { 
     e.printStackTrace(); 
     return Optional.empty(); 
    } 
    } 

    static <T extends Serializable> Optional<T> convertFrom(final String objectAsString) { 
    final byte[] data = Base64.getDecoder().decode(objectAsString); 
    try (final ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data))) { 
     return Optional.of((T) ois.readObject()); 
    } catch (final IOException | ClassNotFoundException e) { 
     e.printStackTrace(); 
     return Optional.empty(); 
    } 
    } 
} 
0

簡單的解決方案,爲我工作

public static byte[] serialize(Object obj) throws IOException { 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    ObjectOutputStream os = new ObjectOutputStream(out); 
    os.writeObject(obj); 
    return out.toByteArray(); 
} 
相關問題