Jak serializować obiekt do ciągu znaków

Jestem w stanie serializować obiekt do pliku, a następnie przywrócić go ponownie, Jak pokazano w następnym fragmencie kodu. Chciałbym serializować obiekt do ciągu znaków i zapisać go w bazie danych. Czy ktoś może mi pomóc?

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();
Author: casperOne, 2008-09-25

14 answers

Sergio:

Powinieneś użyć BLOB . Z JDBC jest całkiem prosto.

Problem z drugim kodem, który napisałeś, to kodowanie. Należy dodatkowo zakodować bajty, aby upewnić się, że żaden z nich nie zawiedzie.

Jeśli nadal chcesz zapisać go do ciągu znaków, możesz kodować bajty za pomocą java.util.Base64 .

Nadal powinieneś używać CLOB jako typu danych, ponieważ nie wiesz, jak długo będą przechowywane dane seryjne.

Tutaj jest próbką jak go używać.

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

Wyjście:

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

Uwaga : dla Javy 7 i wcześniejszych możesz zobaczyć oryginalną odpowiedź tutaj

 275
Author: OscarRyz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:33

A może zapisanie danych do strumienia ByteArrayOutputStream zamiast pliku?

W przeciwnym razie możesz serializować obiekt za pomocą XMLEncoder, utrzymywać XML, a następnie deserializować za pomocą XMLDecoder.

 12
Author: Outlaw Programmer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 16:58:08

Dzięki za świetne i szybkie odpowiedzi. Oddam kilka głosów natychmiast, aby potwierdzić twoją pomoc. W oparciu o Wasze odpowiedzi napisałem najlepsze rozwiązanie.

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

Uwaga nie rozważałem używania JSON, ponieważ jest mniej wydajny.

Uwaga: rozważę twoją radę, aby nie przechowywać serializowanych obiektów jako łańcuchów w bazie danych, ale zamiast tego bajt [].

 8
Author: Sergio del Amo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 17:19:25

Java8 approach, konwertujący obiekt z / na String, inspirowany odpowiedzią z OscarRyz. Dla de-/encoding, java.util.Base64 jest wymagane i używane.

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();
    }
  }
}
 5
Author: Markus Schulte,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-18 12:31:04

XStream zapewnia proste narzędzie do serializacji/deserializacji do / Z XML, i to jest Bardzo szybkie. Przechowywanie Klobów XML zamiast binarnych BLOBÓW będzie mniej kruche, nie wspominając o bardziej czytelnym.

 4
Author: skaffman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 19:57:15

Co powiesz na utrzymywanie obiektu jako blob

 4
Author: Kristian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-05 15:39:40

Jeśli przechowujesz obiekt jako dane binarne w bazie danych, powinieneś użyć typu BLOB. Baza danych jest w stanie przechowywać go bardziej wydajnie, i nie musisz się martwić o kodowanie i tym podobne. JDBC dostarcza metody tworzenia i pobierania obiektów blob w kategoriach strumieni. Użyj Javy 6, jeśli możesz, to wprowadziło kilka dodatków do JDBC API, które znacznie ułatwiają radzenie sobie z blobami.

Jeśli koniecznie musisz przechowywać dane jako ciąg znaków, polecam XStream dla pamięci masowej opartej na XML( znacznie łatwiej niż XMLEncoder), ale alternatywne reprezentacje obiektów mogą być równie przydatne (np. JSON). Twoje podejście zależy od tego, dlaczego tak naprawdę musisz przechowywać obiekt w ten sposób.

 3
Author: Daniel Spiewak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 17:04:24

Spójrz na Javę.sql.PreparedStatement class, specifically the function

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

Następnie spójrz na java.sql.Klasa ResultSet, a konkretnie funkcja

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

Należy pamiętać, że jeśli serializujesz obiekt do bazy danych, a następnie zmieniasz obiekt w kodzie w nowej wersji, proces deserializacji może się łatwo nie udać, ponieważ zmienił się podpis Twojego obiektu. Kiedyś popełniłem ten błąd z przechowywaniem niestandardowych preferencji serializowanych, a następnie dokonując zmiany definicji preferencji. Nagle nie mogłem odczytać żadnej z wcześniej serializowanych informacji.

Może lepiej pisać w tabelce o kolumnach właściwości i komponować i rozkładać obiekt w ten sposób, aby uniknąć problem z wersjami obiektów i deserializacją. Lub zapisanie właściwości do hashmapy jakiegoś rodzaju, jak java.util.Obiekt Properties, a następnie serializowanie obiektu properties, które jest bardzo mało prawdopodobne, aby zmienić.

 2
Author: Josh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 21:08:40

Serializowany strumień jest tylko sekwencją bajtów (oktetów). Więc pytanie brzmi, jak przekonwertować sekwencję bajtów na ciąg znaków i z powrotem. Ponadto musi używać ograniczonego zestawu kodów znaków, jeśli ma być przechowywany w bazie danych.

Oczywistym rozwiązaniem problemu jest zmiana pola na binarny LOB. Jeśli chcesz trzymać się characer LOB, musisz zakodować w jakimś schemacie, takim jak base64, hex lub uu.

 1
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 17:05:11

Możesz użyć kompilacji w klasach sun.misc.Base64Decoder i sun.misc.Base64Encoder do konwersji danych binarnych serialize na ciąg znaków. Nie potrzebujesz dodatkowych klas, ponieważ są one wbudowane.

 1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 18:38:18

Proste rozwiązanie, zadziałało dla mnie

public static byte[] serialize(Object obj) throws IOException {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream os = new ObjectOutputStream(out);
    os.writeObject(obj);
    return out.toByteArray();
}
 1
Author: priyanka_rao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-20 07:19:15

Możesz użyć UUEncoding

 0
Author: CiNN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 17:03:06

Obecnie najbardziej oczywistym podejściem jest zapisanie obiektu(obiektów) do JSON.

  1. JSON jest czytelny
  2. JSON jest bardziej czytelny i łatwiejszy w obsłudze niż XML.
  3. wiele baz danych innych niż SQL, które umożliwiają bezpośrednie przechowywanie JSON.
  4. twój klient komunikuje się już z serwerem za pomocą JSON. (Jeśli nie, jest to bardzo prawdopodobne błąd.)

Przykład użycia 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 umożliwia konwersję listy bezpośrednio. Przykłady może być łatwo wygooglowane. Wolę najpierw konwertować listy na tablice.

 0
Author: yurin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-28 10:04:49

Użyj frameworka O / R, takiego jak hibernate

 -3
Author: Kristian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-25 16:59:33