Pergunta

Eu tenho uma classe que eu preciso para serialize binário. A classe contém um campo como abaixo:

private T[,] m_data;

Estes arrays multi-dimensionais pode ser bastante grande (centenas de milhares de elementos) e de qualquer tipo primitivo. Quando eu tentei serialização .net padrão em um objeto o arquivo gravado em disco era grande e eu acho que .net é armazenar uma grande quantidade de dados repetidos sobre tipos de elementos e, possivelmente, não tão eficiente quanto poderia ser feito.

Eu olhei em torno de serializers personalizados, mas não vi nenhum que lidam com matrizes genéricos multi-dimensionais. Eu também experimentei com built-in de compressão de .NET em um array de bytes do fluxo de memória após a serialização com algum sucesso, mas não tão rápido / comprimido como eu esperava.

A minha pergunta é, devo tentar escrever um serializador personalizado para otimizar serializar essa matriz para o tipo apropriado (isto parece um pouco assustador), ou devo usar serialização .net padrão e adicionar compressão?

Qualquer conselhos sobre a melhor abordagem seria mais apreciada, ou links para recursos mostrando como lidar com a serialização de uma matriz genérica multi-dimensional - como mencionado exemplos existentes eu encontrei não suportam tais estruturas.

Foi útil?

Solução

Aqui está o que eu vim acima com. O código a seguir faz um int [1000] [10000] e escreve-lo usando o BinaryFormatter para 2 arquivos - um compactado e não um.

O arquivo compactado é 1,19 MB (1,255,339 bytes) Unzipped é de 38,2 MB (40,150,034 bytes)

        int width = 1000;
        int height = 10000;
        List<int[]> list = new List<int[]>();
        for (int i = 0; i < height; i++)
        {
            list.Add(Enumerable.Range(0, width).ToArray());
        }
        int[][] bazillionInts = list.ToArray();
        using (FileStream fsZ = new FileStream("c:\\temp_zipped.txt", FileMode.Create))
        using (FileStream fs = new FileStream("c:\\temp_notZipped.txt", FileMode.Create))
        using (GZipStream gz = new GZipStream(fsZ, CompressionMode.Compress))
        {
            BinaryFormatter f = new BinaryFormatter();
            f.Serialize(gz, bazillionInts);
            f.Serialize(fs, bazillionInts);
        }

Eu não consigo pensar em uma maneira melhor / fácil de fazer isso. A versão compactada é muito muito apertado.

Eu iria com o BinaryFormatter + GZipStream. Fazer algo personalizado não seria divertido.


[editar por MG] Eu espero que você não vai ser ofendido por uma edição, mas o uniforme repetida Range (0, largura) é coisas desviando vastamente; mudança:

        int width = 1000;
        int height = 10000;
        Random rand = new Random(123456);
        int[,] bazillionInts = new int[width, height];
        for(int i = 0 ; i < width;i++)
            for (int j = 0; j < height; j++)
            {
                bazillionInts[i, j] = rand.Next(50000);
            }

E experimentá-lo; você verá temp_notZipped.txt em 40MB, temp_zipped.txt em 62MB. Não tão atraente ...

Outras dicas

A melhor proporção de tamanho comprimento de código / saída seria para codificar a sua matriz usando BitConverter, convertendo todos os elementos em seu formato binário compacto. É o manual, eu sei, mas vai economizar espaço de 80-90% em relação ao .NET binário serialização.

Você pode definir "grande"? O exemplo 1000x10000xint (outro post) sai em 40Mb; e 1000x10000x4 bytes (= int) é 38MB. Como overheads ir, que não é terrível.

Que tipo de dados é T provável que seja? primatives justo? Eu estou pensando que eu provavelmente poderia editar protobuf-net para apoiar arrays* rectangular - mas para manter algum tipo de fio-compatibilidade nós provavelmente precisa de um cabeçalho (um byte) per elemento -. ou seja, 9MB de sobrecarga para o exemplo 1000x10000

Isso provavelmente não vale a pena para coisas como float, double, etc (uma vez que são armazenados na íntegra em "protocolo buffers") - mas pode haver poupança para coisas como int simplesmente devido à forma como ele embala ints ... (especialmente se eles tendem a estar no lado menor [magnitude]). Finalmente, se T é realmente objetos como Person etc, então ele deve ser um muito melhor do que serialização binária, uma vez que é muito bom em embalagem objetos.

Não seria trivial para shoe-horn na matrizes retangulares, mas deixe-me saber se isso é algo que você estaria interessado em tentar.

*: isso não acontece no momento desde os "buffers de protocolo" especificação não apoiá-los, mas podemos cortar em torno disso ...

A razão é preciso haver tantos dados sobre os tipos é que o seu leque de T pode ser qualquer tipo, mas mais especificamente, T poderia ser do tipo SomeBaseClass, e você ainda pode armazenar SomeDerivedClass nessa matriz, eo desserializador seria preciso saber isso.

Mas esses dados redundantes torna um bom candidato para a compressão, como os outros.

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