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

Foi útil?

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

Aqui está um artigo de Sun sobre isso.

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top