Подтвердить что ты не робот

Как использовать GZipStream с System.IO.MemoryStream?

У меня возникла проблема с этой тестовой функцией, где я беру строку в памяти, сжимаю ее и распаковываю. Сжатие работает отлично, но я не могу заставить декомпрессию работать.

//Compress
System.IO.MemoryStream outStream = new System.IO.MemoryStream();                
GZipStream tinyStream = new GZipStream(outStream, CompressionMode.Compress);
mStream.Position = 0;
mStream.CopyTo(tinyStream);

//Decompress    
outStream.Position = 0;
GZipStream bigStream = new GZipStream(outStream, CompressionMode.Decompress);
System.IO.MemoryStream bigStreamOut = new System.IO.MemoryStream();
bigStream.CopyTo(bigStreamOut);

//Results:
//bigStreamOut.Length == 0
//outStream.Position == the end of the stream.

Я считаю, что у BigStream должно быть хотя бы данные в нем, особенно если мой исходный поток (outStream) читается. это ошибка MSFT или моя?

4b9b3361

Ответ 1

Что происходит в вашем коде, так это то, что вы продолжаете открывать потоки, но никогда не закрываете их.

  • В строке 2 вы создаете GZipStream. Этот поток не будет записывать ничего в основной поток, пока он не почувствует его правильное время. Вы можете сказать это, закрыв его.

  • Однако, если вы закроете его, он также закроет базовый поток (outStream). Поэтому вы не можете использовать mStream.Position = 0 на нем.

Вы всегда должны использовать using, чтобы убедиться, что все ваши потоки закрыты. Вот вариант вашего кода, который работает.

var inputString = "" ... "";
byte[] compressed;
string output;

using (var outStream = new MemoryStream())
{
    using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
    using (var mStream = new MemoryStream(Encoding.UTF8.GetBytes(inputString)))
        mStream.CopyTo(tinyStream);

    compressed = outStream.ToArray();
}

// "compressed" now contains the compressed string.
// Also, all the streams are closed and the above is a self-contained operation.

using (var inStream = new MemoryStream(compressed))
using (var bigStream = new GZipStream(inStream, CompressionMode.Decompress))
using (var bigStreamOut = new MemoryStream())
{
    bigStream.CopyTo(bigStreamOut);
    output = Encoding.UTF8.GetString(bigStreamOut.ToArray());
}

// "output" now contains the uncompressed string.
Console.WriteLine(output);

Ответ 2

Это известная проблема: http://blogs.msdn.com/b/bclteam/archive/2006/05/10/592551.aspx

Я немного изменил свой код, так что он работает:

var mStream = new MemoryStream(new byte[100]);
var outStream = new System.IO.MemoryStream();

using (var tinyStream = new GZipStream(outStream, CompressionMode.Compress))
{
    mStream.CopyTo(tinyStream);           
}

byte[] bb = outStream.ToArray();

//Decompress                
var bigStream = new GZipStream(new MemoryStream(bb), CompressionMode.Decompress);
var bigStreamOut = new System.IO.MemoryStream();
bigStream.CopyTo(bigStreamOut);

Ответ 3

Другая реализация в VB.NET:

Imports System.Runtime.CompilerServices
Imports System.IO
Imports System.IO.Compression

Public Module Compressor

    <Extension()> _
    Function CompressASCII(str As String) As Byte()

        Dim bytes As Byte() = Encoding.ASCII.GetBytes(str)

        Using ms As New MemoryStream

            Using gzStream As New GZipStream(ms, CompressionMode.Compress)

                gzStream.Write(bytes, 0, bytes.Length)

            End Using

            Return ms.ToArray

        End Using

    End Function

    <Extension()> _
    Function DecompressASCII(compressedString As Byte()) As String

        Using ms As New MemoryStream(compressedString)

            Using gzStream As New GZipStream(ms, CompressionMode.Decompress)

                Using sr As New StreamReader(gzStream, Encoding.ASCII)

                    Return sr.ReadToEnd

                End Using

            End Using

        End Using

    End Function

    Sub TestCompression()

        Dim input As String = "fh3o047gh"

        Dim compressed As Byte() = input.CompressASCII()

        Dim decompressed As String = compressed.DecompressASCII()

        If input <> decompressed Then
            Throw New ApplicationException("failure!")
        End If

    End Sub

End Module

Ответ 4

Способ сжатия и распаковки в MemoryStream и из него:

public static Stream Compress(
    Stream decompressed, 
    CompressionLevel compressionLevel = CompressionLevel.Fastest)
{
    var compressed = new MemoryStream();
    using (var zip = new GZipStream(compressed, compressionLevel, true))
    {
        decompressed.CopyTo(zip);
    }

    compressed.Seek(0, SeekOrigin.Begin);
    return compressed;
}

public static Stream Decompress(Stream compressed)
{
    var decompressed = new MemoryStream();
    using (var zip = new GZipStream(compressed, CompressionMode.Decompress, true))
    {
        zip.CopyTo(decompressed);
    }

    decompressed.Seek(0, SeekOrigin.Begin);
    return decompressed;
}

Это оставляет сжатый/распакованный поток открытым и как можно использовать после его создания.

Ответ 5

    public static byte[] compress(byte[] data)
    {
        using (MemoryStream outStream = new MemoryStream())
        {
            using (GZipStream gzipStream = new GZipStream(outStream, CompressionMode.Compress))
            using (MemoryStream srcStream = new MemoryStream(data))
                srcStream.CopyTo(gzipStream);
            return outStream.ToArray();
        }
    }

    public static byte[] decompress(byte[] compressed)
    {
        using (MemoryStream inStream = new MemoryStream(compressed))
        using (GZipStream gzipStream = new GZipStream(inStream, CompressionMode.Decompress))
        using (MemoryStream outStream = new MemoryStream())
        {
            gzipStream.CopyTo(outStream);
            return outStream.ToArray();
        }
    }

Ответ 6

Если вы пытаетесь использовать MemoryStream (например, передаете его в другую функцию), но получаете исключение "Невозможно получить доступ к закрытому потоку". то есть другой конструктор GZipStream, который вы можете использовать, который вам поможет.

Передавая истину параметру leaveOpen, вы можете указать GZipStream оставить поток открытым после утилизации самого себя, по умолчанию он закрывает целевой поток (чего я не ожидал). https://msdn.microsoft.com/en-us/library/27ck2z1y(v=vs.110).aspx

using (FileStream fs = File.OpenRead(f))
using (var compressed = new MemoryStream())
{
    //Instruct GZipStream to leave the stream open after performing the compression.
    using (var gzipstream = new GZipStream(compressed, CompressionLevel.Optimal, true))
        fs.CopyTo(gzipstream);

    //Do something with the memorystream
    compressed.Seek(0, SeekOrigin.Begin);
    MyFunction(compressed);
}

Ответ 7

Если вы все еще нуждаетесь в этом, вы можете использовать конструктор GZipStream с логическим аргументом (есть два таких конструктора) и передать там истинное значение:

tinyStream = new GZipStream(outStream, CompressionMode.Compress, true);

В этом случае, когда вы закроете свой tynyStream, ваш поток будет открыт. Не забудьте скопировать данные:

mStream.CopyTo(tinyStream);
tinyStream.Close();

Теперь у вас есть поток данных outStream с заархивированными данными

Ошибки и поцелуи для U

Удачи

Ответ 8

Пожалуйста, обратитесь к ссылке ниже, это не использовать двойной MemoryStream. fooobar.com/info/6694537/...