157

我能够将一个对象序列化为一个文件,然后再次恢复它,如下一个代码片段所示。我想将对象序列化为字符串并存储到数据库中。谁能帮我?

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

13 回答 13

281

塞尔吉奥:

你应该使用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 及更早版本,您可以在此处查看原始答案

于 2008-09-25T18:03:38.973 回答
12

将数据写入 ByteArrayOutputStream 而不是 FileOutputStream 怎么样?

否则,您可以使用 XMLEncoder 序列化对象,持久化 XML,然后通过 XMLDecoder 反序列化。

于 2008-09-25T16:58:08.630 回答
8

感谢您的快速回复。我将立即放弃一些投票以感谢您的帮助。我根据您的回答编写了我认为的最佳解决方案。

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[] 的建议。

于 2008-09-25T17:19:25.897 回答
5

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;

final class ObjectHelper {

  private 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();
    }
  }
}
于 2017-06-02T11:54:42.397 回答
4

如何将对象持久化为blob

于 2008-09-25T17:01:01.807 回答
4

XStream 提供了一个简单的实用程序,用于对 XML 进行序列化/反序列化,而且速度非常快。存储 XML CLOB 而不是二进制 BLOBS 将不那么脆弱,更不用说更具可读性了。

于 2008-09-25T19:57:15.270 回答
3

如果您将对象作为二进制数据存储在数据库中,那么您确实应该使用BLOB数据类型。数据库能够更有效地存储它,您不必担心编码等。JDBC 提供了根据流创建和检索 blob 的方法。如果可以,请使用 Java 6,它为 JDBC API 添加了一些内容,使处理 blob 变得更加容易。

如果您绝对需要将数据存储为字符串,我会推荐XStream用于基于 XML 的存储(比 更容易XMLEncoder),但替代对象表示可能同样有用(例如 JSON)。您的方法取决于为什么您实际上需要以这种方式存储对象。

于 2008-09-25T17:04:24.967 回答
2

看一下 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 对象,然后序列化极不可能更改的属性对象。

于 2008-09-25T18:18:07.237 回答
1

序列化的流只是一个字节序列(八位字节)。所以问题是如何将字节序列转换为字符串,然后再转换回来。此外,如果要将其存储在数据库中,则需要使用一组有限的字符代码。

该问题的明显解决方案是将字段更改为二进制 LOB。如果您想坚持使用字符 LOB,那么您需要以某种方案进行编码,例如 base64、hex 或 uu。

于 2008-09-25T17:05:11.610 回答
1

您可以使用 sun.misc.Base64Decoder 和 sun.misc.Base64Encoder 类中的构建将序列化的二进制数据转换为字符串。你不需要额外的类,因为它是内置的。

于 2008-09-25T18:38:18.577 回答
1

简单的解决方案,为我工作

public static byte[] serialize(Object obj) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(out);
    os.writeObject(obj);
    return out.toByteArray();
}
于 2017-06-20T07:19:15.047 回答
0

你可以使用 UUEncoding

于 2008-09-25T17:03:06.670 回答
0

今天最明显的方法是将对象保存为 JSON。

  1. JSON 可读
  2. JSON 比 XML 更具可读性和更易于使用。
  3. 许多允许直接存储 JSON 的非 SQL 数据库。
  4. 您的客户端已经使用 JSON 与服务器通信。(如果没有,很可能是一个错误。)

使用Gson的示例。

Gson gson = new Gson();
Person[] persons = getArrayOfPersons();
String json = gson.toJson(persons);
System.out.println(json);
//output: [{"name":"Tom","age":11},{"name":"Jack","age":12}]
Person[] personsFromJson = gson.fromJson(json, Person[].class);
//...
class Person {
     public String name;
     public int age;
} 

Gson 允许直接转换 List。例子可以很容易地用谷歌搜索。我更喜欢先将列表转换为数组。

于 2020-10-28T08:38:53.220 回答