C # MemoryStream y GZIPInputStream: No se puede .read más de 256 bytes

votos
1

Estoy teniendo un problema con la escritura de un flujo sin comprimir usando GZIP GZIPInputStream de SharpZipLib. Sólo parece ser capaz de obtener 256 bytes valor de los datos con el resto de no ser por escrito a la izquierda y puesto a cero. La corriente comprimida (compressedSection) ha sido comprobado y todos los datos se allí (1500+ bytes). El fragmento del proceso de descompresión es a continuación:

int msiBuffer = 4096;
                using (Stream msi = new MemoryStream(msiBuffer))
                {
                    msi.Write(compressedSection, 0, compressedSection.Length);
                    msi.Position = 0;
                    int uncompressedIntSize = AllMethods.GetLittleEndianInt(uncompressedSize, 0); // Gets little endian value of uncompressed size into an integer

                    // SharpZipLib GZip method called
                    using (GZipInputStream decompressStream = new GZipInputStream(msi, uncompressedIntSize))
                    {
                        using (MemoryStream outputStream = new MemoryStream(uncompressedIntSize))
                        {
                            byte[] buffer = new byte[uncompressedIntSize];
                            decompressStream.Read(buffer, 0, uncompressedIntSize); // Stream is decompressed and read         
                            outputStream.Write(buffer, 0, uncompressedIntSize);
                            using (var fs = new FileStream(kernelSectionUncompressed, FileMode.Create, FileAccess.Write))
                            {
                                fs.Write(buffer, 0, buffer.Length);
                                fs.Close();
                            }
                            outputStream.Close();
                        }
                        decompressStream.Close();

Así que en este fragmento:

1) La sección de comprimido se pasa en, listo para ser descomprimido.

2) El tamaño esperado de la salida sin comprimir (que se almacena en un encabezado con el archivo como un valor de 2 bytes little-endian) se hace pasar a través de un método para convertir a un entero. La cabecera se retira temprano, ya que no es parte del archivo comprimido GZIP.

3) corriente GZIP de SharpLibZip se declara con el flujo comprimido de archivo (msi) y un tampón igual a int uncompressedIntSize (han probado con un valor estático de 4096 también).

4) He creado un MemoryStream para manejar escribir la salida a un archivo como GZIPInputStream no tiene lectura / escritura; se necesita el tamaño del archivo descomprimido espera como argumento (capacidad).

5) La lectura / escritura de las necesidades de flujo de bytes array [] como primer argumento, por lo que creó un [] matriz de bytes con espacio suficiente para tener todos los bytes de la salida descomprimida (3584 bytes en este caso, derivado de uncompressedIntSize ).

6) int GZIPInputStream decompressStream utiliza .Read con el tampón como primer argumento, desde el desplazamiento 0, utilizando el uncompressedIntSize como el recuento. Comprobación de los argumentos aquí, la matriz del separador todavía tiene una capacidad de 3584 bytes, pero sólo se ha dado 256 bytes de datos. El resto son ceros.

Parece que la salida de .Read está siendo estrangulado a 256 bytes, pero no estoy seguro de dónde. ¿Hay algo que he echado de menos con los arroyos, o se trata de una limitación con .Read?

Publicado el 09/10/2019 a las 19:00
fuente por usuario
En otros idiomas...                            


2 respuestas

votos
2

Usted necesita bucle cuando se lee de una corriente; el perezoso manera es probable que:

decompressStream.CopyTo(outputStream);

(pero esto no garantiza que parar después de uncompressedIntSizebytes - se va a tratar de leer hasta el final de decompressStream)

Una versión más manual (que respete un límite de longitud impuesta) sería:

const int BUFFER_SIZE = 1024; // whatever
var buffer = ArrayPool<byte>.Shared.Rent(BUFFER_SIZE);
try
{
    int remaining = uncompressedIntSize, bytesRead;
    while (remaining > 0 && // more to do, and making progress
        (bytesRead = decompressStream.Read(
        buffer, 0, Math.Min(remaining, buffer.Length))) > 0)
    {
        outputStream.Write(buffer, 0, bytesRead);
        remaining -= bytesRead;
    }
    if (remaining != 0) throw new EndOfStreamException();
}
finally
{
    ArrayPool<byte>.Shared.Return(buffer);
}
Respondida el 09/10/2019 a las 19:10
fuente por usuario

votos
0

El problema resultó ser un descuido que había hecho anteriormente en el código publicado:

El archivo que estoy trabajando tiene 27 secciones que se gzipped, pero cada uno tiene una cabecera que romperá la descompresión gzip si el flujo GZipInput golpea cualquiera de ellos. Al abrir el archivo de base, que estaba empezando desde el principio (ajustado por 6 para evitar la primera cabecera) cada vez en lugar de ir a la siguiente post-cabeza offset:

brg.BaseStream.Seek (6, SeekOrigin.Begin);

En lugar de:

brg.BaseStream.Seek (absoluteSectionOffset, SeekOrigin.Begin);

Esto significaba que los datos comprimidos extraída era una amalgama de la primera sección sin cabeceras + parte de la segunda sección a lo largo con su cabecera. A medida que la primera sección es de 256 bytes de longitud sin su cabecera, esta parte estaba siendo descomprimido correctamente por la corriente GZipInput. Pero después de eso es de 6 bytes de cabecera que lo rompe, lo que resulta en el resto de la salida siendo 00s.

No hubo un error explícito ser arrojado por la corriente GZipInput cuando esto sucedió, así que había asumido erróneamente que la causa fue la .Read o algo en la corriente de retención de datos de la pasada anterior. Perdón por la molestia.

Respondida el 10/10/2019 a las 13:58
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more