1

BigInteger をファイルに書き込みたい。
これを行う最善の方法は何ですか。
もちろん、入力ストリームから(人間ではなくプログラムで)読みたいです。
ObjectOutputStream を使用する必要がありますか、それともより良い方法がありますか?

目的は、できるだけ少ないバイトを使用することです。

ありがとう
マルティン

4

5 に答える 5

8

Javaシリアル化(ObjectOutputStream/ ObjectInputStream)は、オブジェクトをオクテットシーケンスにシリアル化する汎用的な方法です。ただし、シリアル化には問題があります。

非常に効率的であるために、BigInteger持っているtoByteArrayとを取るコンストラクターbyte[]byte[]次に、ストリームで(長さを含めて)表す方法が必要です。たとえば、長さを使用DataOutputStreamwriteIntて、生データを追跡することができます。

もちろん、ストリームは、選択した適切なデコレータを使用して圧縮できます。

于 2009-12-11T19:22:35.590 に答える
3

私は ObjectOutputStream を使用します。これは、それが設計されたものです (具体的には BigInteger ではなく、クラス)。

以下は、圧縮された ObjectOutpuStream と圧縮されていない ObjectOutpuStream の両方のオーバーヘッドを示す簡単なサンプル コードです。

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPOutputStream;


public class Main
{
    public static void main(String[] args)
        throws IOException
    {
        run(1);
        run(10);
        run(100);
        run(1000);
        run(10000);
        run(100000);
        run(1000000);
    }

    private static void run(final int size)
        throws IOException
    {
        final List<BigInteger> values;
        final int              uncompressedSize;
        final int              compressedSize;

        values           = createValues(size);
        uncompressedSize = storeUncompressed(values);
        compressedSize   = storeCompressed(values);

        System.out.println(size + " uncompressed is " + uncompressedSize + " ratio is: " + ((float)uncompressedSize / size));
        System.out.println(size + " compressed   is " + compressedSize   + " ratio is: " + ((float)compressedSize   / size));
    }

    private static List<BigInteger> createValues(final int size)
    {
        final List<BigInteger> values;

        values = new ArrayList<BigInteger>(size);

        for(int i = 0; i < size; i++)
        {
            values.add(BigInteger.ZERO);
        }

        return (values);
    }

    private static int storeUncompressed(final List<BigInteger> values)
        throws IOException
    {
        final ByteArrayOutputStream bytes;

        bytes = new ByteArrayOutputStream();
        store(values, bytes);

        return (bytes.size());
    }


    private static int storeCompressed(final List<BigInteger> values)
        throws IOException
    {
        final ByteArrayOutputStream bytes;
        final GZIPOutputStream      zip;

        bytes = new ByteArrayOutputStream();
        zip   = new GZIPOutputStream(bytes);
        store(values, zip);

        return (bytes.size());
    }

    private static void store(final List<BigInteger> values,
                              final OutputStream     sink)
        throws IOException
    {
        ObjectOutputStream stream;

        stream = null;

        try
        {
            stream = new ObjectOutputStream(sink);

            for(final BigInteger value : values)
            {
                stream.writeObject(value);
            }
        }
        finally
        {
            if(stream != null)
            {
                stream.close();
            }
        }
    }
}

出力は次のとおりです。

1 uncompressed is 202 ratio is: 202.0
1 compressed   is 198 ratio is: 198.0
10 uncompressed is 247 ratio is: 24.7
10 compressed   is 205 ratio is: 20.5
100 uncompressed is 697 ratio is: 6.97
100 compressed   is 207 ratio is: 2.07
1000 uncompressed is 5197 ratio is: 5.197
1000 compressed   is 234 ratio is: 0.234
10000 uncompressed is 50197 ratio is: 5.0197
10000 compressed   is 308 ratio is: 0.0308
100000 uncompressed is 500197 ratio is: 5.00197
100000 compressed   is 962 ratio is: 0.00962
1000000 uncompressed is 5000197 ratio is: 5.000197
1000000 compressed   is 7516 ratio is: 0.007516

「values.add(BigInteger.ZERO);」を変更します。テストをより現実的なものにするための行 - ベースラインが欲しかっただけです。

于 2009-12-11T19:08:24.683 に答える
1

はい、簡単にするためにObjectOutputStream / ObjectInputStreamを使用するか、BigIntegerをbyte []に​​変換して、オブジェクト全体ではなくその値をシリアル化することができます。後者は、オブジェクト全体をシリアル化するよりもかなりの量のストレージスペースを節約します。

また、まだバッファリングされていないストリームクラスを使用する場合は、パフォーマンスを向上させるためにOutputStreamsとInputStreamsをBufferedOutputStreamとBufferedInputStreamでラップし、書き込みが完了したら(flush()をflush()しない場合は、BufferedOutputStream、 InputStreamは、入力を待機して停止またはハングする可能性があります)。

帯域幅やファイルサイズが心配な場合は、ストリームをGZipOutputStream / GZipInputStreamでラップして、自動圧縮することもできます。ただし、実際にパフォーマンスの低下や巨大なファイルが観察されない限り、データの圧縮について心配する必要はありません。

于 2009-12-11T19:19:31.493 に答える
1

編集:質問が最適化に関するものであることに気づきませんでした。

後でシリアル化されたオブジェクトを圧縮して、いくつかのバイトを節約することができます。以下を使用してみてください。

FileOutputStream fos = new 
    FileOutputStream("db");
  GZIPOutputStream gz = new GZIPOutputStream(fos);

これはそれについての太陽による記事です。

于 2009-12-11T19:23:12.890 に答える
1

Object全体またはそののみを読み書きしますか? 前者の場合は、Serializationを使用します。後者の場合は、ByteArrayInputStream/を使用しByteArrayOutputStreamて、結果を記述し、それぞれBigInteger#toByteArray()の助けを借りて新しいものを構築しnew BigInteger(byte[])ます。最後の方法では、明らかに、ファイル内で生成されるバイト数がはるかに少なくなります。

于 2009-12-11T19:15:43.673 に答える