Java: Biginteger, Howa, um es durch einen Ausgangsstream zu schreiben
-
19-09-2019 - |
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
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);
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.