Frage

Ich möchte eine Biginteger in eine Datei schreiben.
Was ist der beste Weg, dies zu tun?
Natürlich möchte ich lesen (mit dem Programm, nicht vom Menschen) es von einem Eingabestream.
Muss ich einen ObjectOutputStream verwenden oder gibt es bessere Wege?

Ziel ist es, so weniger Bytes wie möglich zu verwenden.

Vielen Dank
Martijn

War es hilfreich?

Lösung

Java -Serialisierung (ObjectOutputStream/ObjectInputStream) ist ein allgemeiner Weg, um Objekte in Oktettsequenzen zu senken. Es gibt jedoch Probleme mit der Serialisierung.

Überaus effizient sein, BigInteger hat toByteArray und ein Konstruktor, der nimmt byte[]. Dann brauchen Sie einen Weg, um darzustellen byte[] (einschließlich Länge) in einem Strom. Zum Beispiel könnten Sie verwenden DataOutputStream zu writeInt die Länge und folgen Sie dem mit den Rohdaten.

Ströme können natürlich mit einem geeigneten Dekorateur Ihrer Wahl komprimiert werden.

Andere Tipps

Ich würde mich für ObjectOutputStream entscheiden, dafür wurde es entwickelt (nicht speziell Biginteger, sondern Klassen).

Hier ist ein schneller Beispielcode, der den Overhead sowohl für komprimierte als auch für unkomprimierte ObjektOutoutpustreams zeigt.

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

Die Ausgabe ist:

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

Sie würden die "values.add (biginteger.zero) ändern;" Zeile, um den Test realistischer zu machen - ich wollte nur eine Grundlinie dafür.

Bearbeitet: Ich wusste nicht, dass es sich bei der Frage um Optimierung handelte.

Sie können das serialisierte Objekt danach komprimieren, um einige Bytes zu speichern. Versuchen Sie, Folgendes zu verwenden.

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

Hier ist ein Artikel von Sun darüber.

Ja, Sie können ObjectOutputStream/ObjectInputStream für den Einfachheit halber verwenden, oder Sie können den Biginterger in ein Byte [] umwandeln und diesen Wert anstelle des gesamten Objekts serialisieren. Letzteres würde eine erhebliche Menge an Speicherplatz bei der Serialisierung des gesamten Objekts sparen.

Wenn Sie Stream -Klassen verwenden, die noch nicht gepuffert sind, denken Sie daran, Ihre Ausgangsstreams und InputStreams in BufferedOutputStream und BufferedInputStream zu wickeln, um die Leistung zu verbessern, und Flush () nach dem Schreiben (wenn Sie nicht bündig () den BufferedOutputStream haben, Der InputStream kann zum Stillstand stehen oder auf Eingabe warten).

Wenn Sie sich Sorgen um Bandbreiten oder Dateigröße machen, können Sie Ihre Streams auch in gzipoutputStream/gzipinputStream zur automatischen Komprimierung einwickeln. Ich würde mir jedoch keine Sorgen machen, die Daten zu komprimieren, es sei denn, Sie beobachten tatsächlich schlechte Leistung oder große Dateien.

Möchten Sie das Ganze lesen/schreiben? Object oder nur sein Wert? Wenn er erstere, dann verwenden Sie von Serialisierung. Wenn letztere, dann verwenden Sie einfach von ByteArrayInputStream/ByteArrayOutputStream wobei Sie das Ergebnis von schreiben BigInteger#toByteArray() und bauen eine neue mit Hilfe von new BigInteger(byte[]) beziehungsweise. Der letzte Weg erzeugt offensichtlich viel weniger Bytes in der Datei.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top