2008-09-25 4 views
126

Ich bin in der Lage, ein Objekt in eine Datei zu serialisieren und dann wieder wie im nächsten Codeausschnitt dargestellt wiederherzustellen. Ich möchte das Objekt in eine Zeichenfolge serialisieren und stattdessen in einer Datenbank speichern. Kann mir jemand helfen?Wie ein Objekt in eine Zeichenfolge zu serialisieren

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

Antwort

242

Sergio:

sollten Sie BLOB verwenden. Es ist ziemlich geradlinig mit JDBC.

Das Problem mit dem zweiten Code, den Sie gepostet haben, ist die Codierung. Sie sollten zusätzlich die Bytes codieren, um sicherzustellen, dass keine von ihnen fehlschlägt.

Wenn Sie es immer noch in einen String schreiben möchten, können Sie die Bytes mit java.util.Base64 codieren.

Immer noch sollten Sie CLOB als Datentyp verwenden, weil Sie nicht wissen, wie lange die serialisierten Daten sein werden.

Hier ist ein Beispiel, wie man es benutzt.

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

Ausgang:

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 

HINWEIS: für Java 7 und früher können Sie die ursprüngliche answer here

+41

+1 für viel Mühe in diese Antwort. –

+0

+1, wenn Sie wirklich Zeichenfolgen benötigen, dann ist base64 + clob der Weg zu gehen. –

+6

+1, Kleine Verbesserung. Besser die Schnittstelle Serializable anstelle von plain Object in der Methode toString() zu verwenden: private static String toString (Serializable object) – zinovii

11

Wie wäre es die Daten an einen ByteArrayOutputStream anstelle eines Fileoutputstream zu schreiben?

Andernfalls können Sie das Objekt mit XMLEncoder serialisieren, das XML persistieren und dann über XMLDecoder deserialisieren.

4

Verwenden Wie wäre es als das Objekt persistierenden blob

0

können Sie uuencoding

3

verwenden Wenn Sie ein Objekt als binäre Daten in der Datenbank sind die Speicherung , dann sollten Sie wirklich einen BLOB Datentyp verwenden. Die Datenbank ist in der Lage, sie effizienter zu speichern, und Sie müssen sich nicht um Kodierungen und Ähnliches kümmern. JDBC bietet Methoden zum Erstellen und Abrufen von Blobs in Form von Streams. Verwenden Sie Java 6, wenn Sie können, hat es einige Ergänzungen der JDBC-API gemacht, die den Umgang mit Blobs viel einfacher machen.

Wenn Sie unbedingt die Daten als String speichern müssen, würde ich XStream für XML-basierten Speicher empfehlen (viel einfacher als XMLEncoder), aber alternative Objektrepräsentationen könnten genauso nützlich sein (z. B. JSON). Ihre Vorgehensweise hängt davon ab, warum Sie das Objekt tatsächlich auf diese Weise speichern müssen.

1

Der serialisierte Stream ist nur eine Folge von Bytes (Oktetts). Die Frage ist also, wie man eine Folge von Bytes in einen String und wieder zurück konvertiert. Außerdem muss ein begrenzter Satz von Zeichencodes verwendet werden, wenn er in einer Datenbank gespeichert werden soll.

Die offensichtliche Lösung für das Problem besteht darin, das Feld zu einem binären LOB zu ändern. Wenn Sie bei einem Characer-LOB bleiben möchten, müssen Sie ein Schema wie base64, hex oder uu codieren.

7

Danke für tolle und schnelle Antworten. Ich werde sofort einige Stimmen abgeben, um Ihre Hilfe anzuerkennen. Ich habe die beste Lösung meiner Meinung nach basierend auf Ihren Antworten codiert.

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

Hinweis i betrachtet nicht JSON verwenden, weil weniger effizient ist.

Hinweis: Ich werde Ihren Rat über nicht speichern serialisierte Objekt als Zeichenfolgen in der Datenbank aber byte [] statt betrachtet.

+3

„ByteArrayOutputStream.toString wandelt die * Plattform Standard-Kodierung mit *. Sind Sie sicher, dass Sie das wollen? Besonders als ein beliebiger Byte-Array nicht gültig UTF8 ist. Außerdem wird es in der Datenbank fehlen. " –

+0

Sie sollten den obigen Kommentar von Tom Hawtin ernst nehmen – anjanb

+0

Ganz zu schweigen von der langfristigen Speicherung von serialisierten Objekten ist keine gute Idee und nicht empfohlen –

1

einen Blick auf die java.sql.PreparedStatement Klasse Nehmen Sie sehen, speziell die Funktion

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

Dann nehmen Sie einen Blick auf die java.sql.ResultSet Klasse, insbesondere die Funktion

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

Beachten Sie, dass, wenn Sie ein Objekt in einer Datenbank werden die Serialisierung, und Sie dann in Ihrem Code, um das Objekt ändern In einer neuen Version kann der Deserialisierungsprozess leicht fehlschlagen, weil sich die Signatur des Objekts geändert hat. Ich habe einmal diesen Fehler gemacht, indem ich eine benutzerdefinierte Voreinstellung serialisiert und dann die Voreinstellungsdefinition geändert habe. Plötzlich konnte ich keine der vorher serialisierten Informationen lesen.

Sie sollten besser klobige Pro-Property-Spalten in einer Tabelle schreiben und das Objekt stattdessen auf diese Weise zusammensetzen und zerlegen, um dieses Problem mit Objektversionen und Deserialisierung zu vermeiden. Oder schreiben Sie die Eigenschaften in eine hashmap von einer Art, wie ein java.util.Properties-Objekt, und dann Serialisierung des Eigenschaftenobjekts, das extrem unwahrscheinlich ist, zu ändern.

1

Mit den integrierten Klassen sun.misc.Base64Decoder und sun.misc.Base64Encoder können Sie die Binärdaten der Serialisierung in eine Zeichenfolge konvertieren. Sie brauchen keine zusätzlichen Klassen, weil sie eingebaut sind.

4

XStream bietet ein einfaches Dienstprogramm für die Serialisierung/Deserialisierung von/nach XML, und es ist sehr schnell. Das Speichern von XML-CLOBs anstelle von binären BLOBS wird weniger fragil und nicht zuletzt lesbarer.

0

Java8 Ansatz, Konvertieren von Objekt von/in String, inspiriert von Antwort von OscarRyz. Zur De-/Encodierung wird java.util.Base64 benötigt und verwendet.

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

einfache Lösung, arbeitete für mich

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