Java: biginteger, como escrevê -lo através de um outputstream
-
19-09-2019 - |
Pergunta
Eu quero escrever um biginteger em um arquivo.
Qual é a melhor maneira de fazer isso.
Claro que quero ler (com o programa, não por humanos) de um inputStream.
Eu tenho que usar um objectOutputStream ou existem maneiras melhores?
O objetivo é usar o mais bytes possível.
Obrigado
Martijn
Solução
Serialização de Java (ObjectOutputStream
/ObjectInputStream
) é uma maneira de propósito geral, ER, serializar objetos em sequências de octeto. No entanto, há problemas com a serialização.
Ser super eficiente, BigInteger
tem toByteArray
e um construtor que leva byte[]
. Então você precisa de uma maneira de representar byte[]
(incluindo comprimento) em um fluxo. Por exemplo, você pode usar DataOutputStream
para writeInt
o comprimento e siga isso com os dados brutos.
Os fluxos podem, é claro, ser comprimidos com um decorador adequado de sua escolha.
Outras dicas
Eu iria com o ObjectOutputStream, foi para isso que foi projetado (não o BigInteger especificamente, mas as classes).
Aqui está algum código de amostra rápido que mostra a sobrecarga para o objeto compactado e não compactado.
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();
}
}
}
}
A saída é:
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
Você mudaria os "valores.add (biginteger.Zero);" linha para tornar o teste mais realista - eu só queria uma linha de base para isso.
Editado: Eu não percebi que a pergunta era sobre otimização.
Você pode comprimir o objeto serializado depois para salvar alguns bytes. Tente usar o seguinte.
FileOutputStream fos = new
FileOutputStream("db");
GZIPOutputStream gz = new GZIPOutputStream(fos);
Sim, você pode usar o ObjectOutputStream/ObjectInputStream para simplificar ou converter o biginteger em um byte [] e serializar esse valor em vez de todo o objeto. Este último economizaria uma quantidade significativa de espaço de armazenamento em serializar em todo o objeto.
Além disso, se você usar classes de fluxo que ainda não estão em buffer, lembre -se de embrulhar seus dados de saída e entrada de entrada em bufferoutputStream e bufferInputStream para melhorar o desempenho, e Flush () depois de terminar de escrever (se você não liberar () o bufferoututputStream, O InputStream pode parar ou ficar esperando por entrada).
Se você estiver preocupado com a largura de banda ou o tamanho do arquivo, também pode envolver seus fluxos no GzipOutputStream/gzipinputStream para compactação automática. No entanto, eu não me preocuparia em comprimir os dados, a menos que você observe um desempenho ruim ou arquivos enormes.
Você quer ler/escrever o todo Object
ou apenas é valor? Se o primeiro, faça uso de Serialização. Se este último, basta usar ByteArrayInputStream
/ByteArrayOutputStream
onde você escreve o resultado de BigInteger#toByteArray()
e construir um novo com ajuda de new BigInteger(byte[])
respectivamente. A última maneira obviamente gera muito menos bytes no arquivo.