1

我想将 BigInteger 写入文件。
做这个的最好方式是什么。
当然,我想从输入流中读取(使用程序,而不是人工)它。
我必须使用 ObjectOutputStream 还是有更好的方法?

目的是使用尽可能少的字节。

谢谢马丁
_

4

5 回答 5

8

Java 序列化 ( ObjectOutputStream/ ObjectInputStream) 是一种通用方法,呃,将对象序列化为八位字节序列。但是,序列化存在问题。

为了超级高效,BigIntegerhastoByteArray和一个构造函数需要byte[]. 然后你需要某种方式byte[]在流中表示(包括长度)。例如,您可以使用DataOutputStream长度writeInt,然后使用原始数据进行跟踪。

当然,可以使用您选择的合适的装饰器来压缩流。

于 2009-12-11T19:22:35.590 回答
3

我会选择 ObjectOutputStream,这就是它的设计目的(不是 BigInteger,而是类)。

这是一些快速示例代码,显示了压缩和未压缩的 ObjectOutpuStreams 的开销。

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

你想读/写整个值Object还是只写它的?如果是前者,则使用Serialization。如果是后者,那么只需使用ByteArrayInputStream/ByteArrayOutputStream在其中编写结果BigInteger#toByteArray()并分别在 of 的帮助下构造一个新结果new BigInteger(byte[])。最后一种方式显然在文件中生成的字节少得多。

于 2009-12-11T19:15:43.673 回答
1

是的,为了简单起见,您可以使用 ObjectOutputStream/ObjectInputStream,或者您可以将 BigInteger 转换为 byte[],并序列化该值而不是整个 Object。与序列化整个对象相比,后者将节省大量存储空间。

此外,如果您使用尚未缓冲的流类,请记住将 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);

这是 sun 的一篇关于它的文章。

于 2009-12-11T19:23:12.890 回答