如何将对象序列化为字符串
我能够将一个对象序列化为一个文件,然后再次还原它,如下面的代码片段所示。我想将对象序列化为字符串并存储到数据库中。谁能帮我?
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();
解决方案
如何将数据写入ByteArrayOutputStream而不是FileOutputStream?
否则,我们可以使用XMLEncoder序列化对象,保留XML,然后通过XMLDecoder反序列化。
使用O / R框架,例如休眠
如何将对象持久保存为Blob
你可以使用UUEncoding
如果要将对象作为二进制数据存储在数据库中,那么我们确实应该使用BLOB
数据类型。数据库能够更有效地存储它,而我们不必担心编码等问题。 JDBC提供了用于根据流创建和检索Blob的方法。如果可以的话,请使用Java 6,它对JDBC API进行了一些补充,使处理blob变得更加容易。
如果我们绝对需要将数据存储为String,我建议使用XStream进行基于XML的存储(比XMLEncoder容易得多),但是替代对象表示可能同样有用(例如JSON)。方法取决于我们为什么实际需要以这种方式存储对象。
序列化的流只是一个字节序列(八位字节)。因此,问题是如何将字节序列转换为String,然后再次转换为String。此外,如果要将其存储在数据库中,则需要使用一组有限的字符代码。
解决该问题的明显方法是将字段更改为二进制LOB。如果要坚持使用字符型LOB,则需要使用某种方案进行编码,例如base64,hex或者uu。
感谢迅速答复。我会在中间放弃一些票以感谢帮助。根据回答,我认为最好的解决方案已经编码。
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 []存储为数据库。
塞尔吉奥:
我们应该使用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和更早版本,我们可以在此处看到原始答案
看一看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对象),然后序列化极不可能更改的属性对象。
我们可以使用类sun.misc.Base64Decoder和sun.misc.Base64Encoder中的构建将序列化的二进制数据转换为字符串。我们不需要添加的类,因为它是内置的。
XStream提供了一个简单的实用程序,用于对XML进行序列化/反序列化,并且非常快捷。存储XML CLOB而不是二进制BLOBS将变得不那么脆弱,更不用说可读性了。