Java: BigInteger, come scriverlo attraverso un OutputStream
-
19-09-2019 - |
Domanda
Voglio scrivere un BigInteger in un file.
Qual è il modo migliore per farlo.
Certo che voglio leggere (con il programma, non da umani) da un InputStream.
Devo usare un ObjectOutputStream o sono modi ci migliori?
Lo scopo è quello di utilizzare come meno byte come possibile.
Grazie
Martijn
Soluzione
Java serializzazione (ObjectOutputStream
/ ObjectInputStream
) è un modo di uso generale, er, serializzazione oggetti in sequenze ottetto. Tuttavia, ci sono problema con la serializzazione.
Per essere super efficiente, BigInteger
ha toByteArray
e un costruttore che prende byte[]
. Allora avete bisogno di qualche modo per rappresentare byte[]
(compresa la lunghezza) in un flusso. Per esempio, si potrebbe usare per DataOutputStream
writeInt
la lunghezza, e seguire che con i dati grezzi.
Streams può, naturalmente, essere compressi con un adeguato decoratrice di vostra scelta.
Altri suggerimenti
Mi piacerebbe andare con ObjectOutputStream, questo è ciò che è stato progettato per (non BigInteger specifico, ma le classi).
Ecco alcuni esempi di codice veloce che mostra la testa per entrambe le ObjectOutpuStreams compresssed e non compressi.
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();
}
}
}
}
L'output è:
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
Si potrebbe cambiare il "values.add (BigInteger.ZERO);" la linea per rendere il test più realistico -. Volevo solo una linea di base per esso
Modificato:. non mi rendevo conto la domanda era una di ottimizzazione
Si potrebbe comprimere l'oggetto serializzato in seguito per salvare alcuni byte. Provare a utilizzare il seguente.
FileOutputStream fos = new
FileOutputStream("db");
GZIPOutputStream gz = new GZIPOutputStream(fos);
Sì, è possibile utilizzare ObjectOutputStream / ObjectInputStream per semplicità, oppure è possibile convertire il BigInteger ad un byte [], e serializzare il valore anziché l'intero oggetto. Quest'ultimo permetterebbe di risparmiare una notevole quantità di spazio di archiviazione sopra la serializzazione l'intero oggetto.
Inoltre, se si utilizza classi stream che non siano già sottoposti a buffering, ricordarsi di avvolgere le OutputStreams e InputStreams in BufferedOutputStream e BufferedInputStream per migliorare le prestazioni, e flush () dopo aver finito di scrivere (se non a filo () il BufferedOutputStream, InputStream potrebbe andare in stallo o appendere in attesa di input).
Se siete preoccupati per la larghezza di banda o la dimensione del file, si può anche avvolgere i flussi in GZIPOutputStream / GZipInputStream per la compressione automatica. Io non mi preoccuperei di compressione dei dati a meno che effettivamente osservate file povere prestazioni o enormi, tuttavia.
Vuoi leggere / scrivere l'intero Object
o solo il suo Valore ? Nel primo caso, quindi fare uso di serializzazione . In quest'ultimo caso, poi basta fare uso di ByteArrayInputStream
/ ByteArrayOutputStream
in cui si scrive il esito BigInteger#toByteArray()
e costruire uno nuovo con l'aiuto di new BigInteger(byte[])
rispettivamente. L'ultimo modo genera, ovviamente, molto meno byte nel file.