2008-09-25 28 views
126

Puedo serializar un objeto en un archivo y luego restaurarlo de nuevo como se muestra en el siguiente fragmento de código. Me gustaría serializar el objeto en una cadena y almacenarlo en una base de datos. ¿Alguien puede ayudarme?Cómo serializar un objeto en una cadena

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

Respuesta

242

Sergio:

Debe utilizar BLOB. Es bastante directo con JDBC.

El problema con el segundo código que ha publicado es la codificación. También debe codificar los bytes para asegurarse de que ninguno de ellos falle.

Si aún desea escribirlo en una Cadena, puede codificar los bytes usando java.util.Base64.

Todavía debe usar CLOB como tipo de datos porque no sabe cuánto tiempo van a ser los datos serializados.

Aquí hay un ejemplo de cómo usarlo.

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; 
    } 
} 

Salida:

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 

NOTA: para Java 7 y versiones anteriores se puede ver el original answer here

+41

+1 por poner mucho esfuerzo en esta respuesta. –

+0

+1 si realmente NECESITA cadenas, entonces base64 + clob es el camino a seguir. –

+6

+1, Pequeña mejora. Es mejor utilizar la interfaz Serializable en lugar de simple Objeto en el método toString() static private String toString (objeto Serializable) – zinovii

11

¿Cómo escribir los datos a un ByteArrayOutputStream en lugar de un FileOutputStream?

De lo contrario, podría serializar el objeto utilizando XMLEncoder, persistir el XML, luego deserializar a través de XMLDecoder.

0

puede utilizar uuencoding

3

Si usted está almacenando un objeto como datos binarios en la base de datos , entonces realmente debería usar un tipo de datos BLOB. La base de datos puede almacenarla de manera más eficiente, y usted no tiene que preocuparse por codificaciones y cosas por el estilo. JDBC proporciona métodos para crear y recuperar blobs en términos de secuencias. Use Java 6 si puede, hizo algunas adiciones a la API de JDBC que hacen que lidiar con blobs sea mucho más fácil.

Si es absolutamente necesario para almacenar los datos como una cadena, lo recomendaría XStream para el almacenamiento basado en XML (mucho más fácil que XMLEncoder), pero las representaciones de objeto alternativa podría ser tan útil (por ejemplo JSON). Su enfoque depende de por qué realmente necesita almacenar el objeto de esta manera.

1

La secuencia serializada es solo una secuencia de bytes (octetos). Entonces la pregunta es cómo convertir una secuencia de bytes a una Cadena, y viceversa. Además, necesita utilizar un conjunto limitado de códigos de caracteres si se va a almacenar en una base de datos.

La solución obvia al problema es cambiar el campo a un LOB binario. Si quieres quedarte con un LOB characer, entonces necesitarás codificar en algún esquema como base64, hex o uu.

7

Gracias por respuestas fabulosas y rápidas. Daré algunos votos inmediatamente para agradecer su ayuda. En mi opinión, he codificado la mejor solución en función de sus respuestas.

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

Nota no me considerado el uso de JSON, porque es menos eficiente.

Nota: Consideraré su consejo sobre no almacenar objetos serializados como cadenas en la base de datos, sino byte [] en su lugar.

+3

"ByteArrayOutputStream.toString convierte el uso de la plataforma de codificación por defecto * *. ¿Seguro que quieres eso? Particularmente como una matriz de bytes arbitraria no es válida UTF8. Además, la base de datos lo va a arruinar ". –

+0

Debe tomar en serio el comentario anterior de Tom Hawtin – anjanb

+0

Sin mencionar el almacenamiento a largo plazo de objetos serializados no es una gran idea y no se recomienda –

1

Tome un vistazo a la clase java.sql.PreparedStatement, específicamente la función

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

Luego echar un vistazo a la clase java.sql.ResultSet, específicamente la función

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

Tenga en cuenta que si usted está serializando un objeto en una base de datos, y luego se cambia el objeto en su código en una nueva versión, el proceso de deserialización puede fallar fácilmente porque la firma de su objeto ha cambiado. Una vez cometí este error al almacenar una Preferencia personalizada serializada y luego hacer un cambio a la definición de Preferencias. De repente, no pude leer ninguna de las informaciones previamente serializadas.

Puede ser mejor escribir clunky por columnas de propiedad en una tabla y componer y descomponer el objeto de esta manera en su lugar, para evitar este problema con versiones de objeto y deserialización. O escribir las propiedades en un hashmap de algún tipo, como un objeto java.util.Properties, y luego serializar el objeto de propiedades que es muy poco probable que cambie.

1

Puede usar la construcción en las clases sun.misc.Base64Decoder y sun.misc.Base64Encoder para convertir los datos binarios de la serialización en una cadena. No necesita clases adicionales porque está integrado.

4

XStream proporciona una utilidad simple para serializar/deserializar a/desde XML, y es muy rápido. Almacenar CLOB XML en lugar de BLOBS binarios va a ser menos frágil, por no mencionar más legible.

0

Enfoque Java8, convertir Objeto de/a Cadena, inspirado en la respuesta de OscarRyz. Para des/codificación, java.util.Base64 es requerido y utilizado.

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

solución simple, que funcionó para mí

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