2008-09-25 51 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(); 
} 
相关问题