web-dev-qa-db-ja.com

オブジェクトを文字列にシリアル化する方法

次のコードスニペットに示すように、オブジェクトをファイルにシリアル化してから復元することができます。オブジェクトを文字列にシリアル化し、代わりにデータベースに保存したいと思います。誰も私を助けることができますか?

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();
144
Sergio del Amo

セルジオ:

BLOB を使用する必要があります。 JDBCを使用すると、非常に簡単です。

投稿した2番目のコードの問題はエンコードです。バイトをさらにエンコードして、それらのいずれも失敗しないことを確認する必要があります。

それでも文字列に書き留めたい場合は、 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

NOTE:Java 7以前の場合、元の 答えはこちら

262
OscarRyz

FileOutputStreamの代わりにByteArrayOutputStreamにデータを書き込むのはどうですか?

それ以外の場合は、XMLEncoderを使用してオブジェクトをシリアル化し、XMLを永続化し、XMLDecoderを介して逆シリアル化できます。

12

素早い返信をありがとう。あなたの助けを認めるために、私はすぐにいくつかの票を投じます。私はあなたの答えに基づいて私の意見で最高のソリューションをコーディングしました。

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 []として保存することについてのアドバイスを検討します。

7
Sergio del Amo

オブジェクトを blob として永続化する方法

4
Kristian

XStreamは、XMLとの間でシリアライズ/デシリアライズするためのシンプルなユーティリティを提供します。これはvery quickです。バイナリBLOBではなくXML CLOBを格納すると、読みやすくなるだけでなく、壊れにくくなります。

4
skaffman

OscarRyz からの回答に触発された、Java8アプローチ、ObjectからStringへの変換。デコード/エンコードの場合、 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();
    }
  }
}
3
Markus Schulte

オブジェクトをデータベースにバイナリデータとして保存する場合は、BLOBデータ型を使用する必要があります。データベースはそれをより効率的に保存でき、エンコードなどを心配する必要はありません。 JDBCは、ストリームの観点からBLOBを作成および取得するためのメソッドを提供します。可能であればJava 6を使用して、BLOBの処理を大幅に簡単にするJDBC APIにいくつかの追加を行いました。

データを文字列として絶対に保存する必要がある場合は、XMLベースのストレージに XStream をお勧めします(XMLEncoderよりもはるかに簡単ですが) JSON)。アプローチは、この方法でオブジェクトを実際に保存する必要がある理由によって異なります。

3
Daniel Spiewak

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オブジェクトなど、何らかの種類のハッシュマップにプロパティを書き込んでから、変更される可能性が極めて低いプロパティオブジェクトをシリアル化します。

1
Josh

シリアル化されたストリームは、単なるバイト(オクテット)のシーケンスです。したがって、問題は、バイトシーケンスを文字列に変換してから元に戻す方法です。さらに、データベースに保存する場合は、限られた文字コードのセットを使用する必要があります。

この問題の明らかな解決策は、フィールドをバイナリLOBに変更することです。文字LOBを使用する場合は、base64、hex、uuなどのスキームでエンコードする必要があります。

クラスSun.misc.Base64DecoderおよびSun.misc.Base64Encoderのビルドを使用して、シリアル化のバイナリデータを文字列に変換できます。組み込みであるため、追加のクラスは必要ありません。

1
Saboteur

uUEncodingを使用できます

0
CiNN

私のために働いたシンプルなソリューション

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