2008-09-25 4 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

Sergio:

Вы должны использовать 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.

3

Если вы храните объект как двоичные данные в базе данных , то вы действительно должны использовать тип данных BLOB. База данных способна хранить ее более эффективно, и вам не нужно беспокоиться о кодировании и т. П. JDBC предоставляет методы для создания и извлечения блоков с точки зрения потоков. Используйте Java 6, если это возможно, он сделал некоторые дополнения к API JDBC, которые упрощают работу с блобами.

Если вам абсолютно необходимо хранить данные в виде строки, я бы рекомендовал XStream для хранения XML на основе (гораздо проще, чем XMLEncoder), но альтернативный объект представления может быть столь же полезным (например, JSON). Ваш подход зависит от того, почему вам действительно нужно хранить объект таким образом.

1

Сериализованный поток - это всего лишь последовательность байтов (октетов). Поэтому вопрос заключается в том, как преобразовать последовательность байтов в строку и обратно. Кроме того, он должен использовать ограниченный набор кодов символов, если он будет храниться в базе данных.

Очевидным решением проблемы является изменение поля на двоичное LOB. Если вы хотите использовать ярлык characer, вам нужно закодировать в какой-то схеме, например 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, потому что является менее эффективным.

Примечание: Я рассмотрю ваш совет о том, чтобы не хранить сериализованный объект в виде строк в базе данных, кроме байт [].

+3

«ByteArrayOutputStream.toString преобразует с помощью * платформы кодировку по умолчанию *. Вы уверены, что хотите этого? В частности, как произвольный массив байт не является действительным UTF8. Кроме того, база данных собирается его калечить ». – 2008-09-25 17:57:44

+0

Вы должны принять вышеуказанный комментарий от Тома Хотина серьезно – 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)

Имейте в виду, что если вы сериализации объекта в базу данных, а затем изменить объект в коде в новой версии процесс десериализации может легко провалиться, потому что подпись вашего объекта изменилась. Я однажды сделал эту ошибку, сохранив пользовательские настройки, сериализованные, а затем внес изменения в определение Preferences. Внезапно я не смог прочитать какую-либо ранее сериализованную информацию.

Возможно, вам лучше писать неудобные столбцы свойств в таблице, а вместо этого компоновать и разлагать объект таким образом, чтобы избежать этой проблемы с объектными версиями и десериализацией. Или записывать свойства в какой-либо хэш-файл, например объект java.util.Properties, а затем сериализовать объект свойств, который вряд ли изменится.

1

Вы можете использовать построить в классах sun.misc.Base64Decoder и sun.misc.Base64Encoder преобразовать двоичные данные сериализации в строку. Вам не нужны дополнительные классы, потому что они встроены.

4

XStream предоставляет простую утилиту для сериализации/десериализации в/из XML и очень быстро. Хранение XML CLOB, а не двоичных BLOBS будет менее хрупким, не говоря уже о более читаемом.

0

Java8 подход, преобразование объекта из/в строку, вдохновленный ответ от 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(); 
} 
Смежные вопросы