2016-01-13 5 views
1

Если вы сжимаете некоторый текст json и записываете его в файл с помощью FileStream, я получаю ожидаемые результаты. Однако я не хочу писать на диск. Я просто хочу запоминать сжатые данные.GZipStream работает при записи в FileStream, но не в MemoryStream

сжатия для FileStream:

string json = Resource1.json; 

using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json))) 
using (FileStream output = File.Create(@"C:\Users\roarker\Desktop\output.json.gz")) 
{ 
    using (GZipStream compression = new GZipStream(output, CompressionMode.Compress)) 
    { 
     input.CopyTo(compression); 
    } 
} 

Над работ. Ниже поток выходной памяти имеет длину 10 и в результате получается пустой .gz-файл.

string json = Resource1.json; 

using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json))) 
using (MemoryStream output = new MemoryStream()) 
{ 
    using (GZipStream compression = new GZipStream(output, CompressionMode.Compress)) 
    { 
     input.CopyTo(compression); 

     byte[] bytes = output.ToArray(); 
    } 
} 

EDIT: Перемещение output.ToArray() за пределами внутреннего using пункта, кажется, работает. Тем не менее, это закрывает выходной поток для большей части использования. IE:

 using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json))) 
     using (MemoryStream output = new MemoryStream()) 
     { 
      using (GZipStream compression = new GZipStream(output, CompressionMode.Compress)) 
      { 
       input.CopyTo(compression); 
      } 
      WriteToFile(output); 
     } 

где:

public static void WriteToFile(Stream stream) 
    { 
     using (FileStream output = File.Create(@"C:\Users\roarker\Desktop\output.json.gz")) 
     { 
      stream.CopyTo(output); 
     } 
    } 

Это потерпит неудачу на stream.CopyTo, потому что поток был закрыт. Я знаю, что могу сделать новый Stream из байтов output.ToArray(), но почему это необходимо? почему ToArray() работают, когда поток закрыт?

Final Edit:

Просто необходимо использовать застройщик в GZipStream с параметром leaveOpen.

+0

Чтобы быть понятным, 'bytes.Length == 10' в конце. – Dave

+1

Получаете ли вы такое же поведение, если вы переместите 'byte [] bytes = output.ToArray();' вне внутреннего 'using' блока? – GalacticCowboy

+3

Потоки похожи на туалеты. Вы не закончили с ними, пока не покраснели. Если вы не какое-то отвратительное животное. Я имею в виду, действительно. – Will

ответ

8

Вы звоните ToArray(), прежде чем закрываете GZipStream ... это означает, что у него не было возможности сбросить последние бит своего буфера. Это общая проблема для сжатия потоков шифрования, где закрытие потока требует записи некоторых окончательных фрагментов данных. (Даже называя Flush() явно не поможет, к примеру.)

Просто переместите ToArray вызов:

using (MemoryStream input = new MemoryStream(Encoding.UTF8.GetBytes(json))) 
using (MemoryStream output = new MemoryStream()) 
{ 
    using (GZipStream compression = new GZipStream(output, CompressionMode.Compress)) 
    { 
     input.CopyTo(compression); 
    } 
    byte[] bytes = output.ToArray(); 
    // Use bytes 
} 

(Обратите внимание, что поток будет расположен при вызове ToArray, но это нормально.)

+0

Я смущен, потому что выходной поток считается закрытым после внутреннего использования. Я могу использовать ToArray() и получить все байты, но я не могу передать 'output' в другую функцию, которая будет рассматриваться как memystream. Имеет ли это смысл? – Dave

+0

@Dave: Да - в основном вы используете дополнительную функциональность «MemoryStream» (что у нее есть данные в памяти), но вы не можете использовать ее как обычный поток. Действительно, очень удобно иметь возможность сделать это именно в такой ситуации. –

+0

Я редактировал вопрос, но я думаю, что вы говорите, что если я хочу получить доступ к этим данным в памяти, мне нужно скопировать эти байты в новый поток? – Dave