2008-11-07 3 views
35

.net에서 이미지를 압축 할 필요가있어서 .net GZipStream 클래스 (또는 DeflateStream)를 사용하여 보았습니다. 그러나 나는 감압이 항상 성공하지 못한다는 것을 알았고 때로는 이미지가 잘 풀리고 다른 시간에 GDI + 오류가 발생하여 무언가가 손상되었다.GZipStream 그리고 DeflateStream은 모든 바이트를 압축 해제하지 않습니다

문제를 조사한 후 압축을 풀면 압축 된 모든 바이트가 반환되지 않는 것으로 나타났습니다. 그래서 2257974 바이트를 압축하면 2257870 바이트 (실수) 만 반환됩니다.

가장 재미있는 점은 가끔 작동한다는 것입니다. 그래서 나는 단지 10 바이트 만 압축하는이 작은 테스트 방법을 만들었지 만 이제는 아무것도 얻지 못합니다.

압축 클래스 GZipStream과 DeflateStream을 사용하여 시도했는데 가능한 코드를 두 번 확인했습니다. 심지어 스트림을 0으로 배치하고 모든 스트림을 플러시하려했지만 운이 없었습니다. 당신은 압축 할 모든 데이터를 추가 한 후 Close()ZipStream 필요

public static void TestCompression() 
    { 
     byte[] test = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

     byte[] result = Decompress(Compress(test)); 

     // This will fail, result.Length is 0 
     Debug.Assert(result.Length == test.Length); 
    } 

    public static byte[] Compress(byte[] data) 
    { 
     var compressedStream = new MemoryStream(); 
     var zipStream = new GZipStream(compressedStream, CompressionMode.Compress); 
     zipStream.Write(data, 0, data.Length); 
     return compressedStream.ToArray(); 
    } 

    public static byte[] Decompress(byte[] data) 
    { 
     var compressedStream = new MemoryStream(data); 
     var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress); 
     var resultStream = new MemoryStream(); 

     var buffer = new byte[4096]; 
     int read; 

     while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0) { 
      resultStream.Write(buffer, 0, read); 
     } 

     return resultStream.ToArray(); 
    } 
+0

댓글을 다시 작성하십시오. - 다양한 레벨의 버퍼로 제공됩니다. 그들이 모두 비운 것이 아니라면 (올바른 순서로) 비어있는 경우 모든 데이터를 얻지 못합니다. –

+0

예를 들어, MemoryStream 자체에서 Close()를 호출하는 것에 신경 쓰지 않았다는 점에 유의하십시오 .- 부분적으로 동의합니다 .-p –

+0

이것에 대한 업데이트도 추가하겠습니다 .... –

답변

48

; 여기

내 코드입니다 쓰여 져야하는 내부적으로 (당신이 Flush() 일지라도) 쓰기되지 않은 바이트의 버퍼를 유지합니다. 당신은 또한 using해야한다, 그래서 더 일반적으로

, StreamIDisposable 각 (예, MemoryStream는 모든 데이터를 잃게하지 않을 것을 알고 있지만,이 습관을하지 않는 경우, 그것은 것 다른 Stream s와 (과) 당신을 물으십시오).

public static byte[] Compress(byte[] data) 
{ 
    using (var compressedStream = new MemoryStream()) 
    using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) 
    { 
     zipStream.Write(data, 0, data.Length); 
     zipStream.Close(); 
     return compressedStream.ToArray(); 
    } 
} 

public static byte[] Decompress(byte[] data) 
{ 
    using(var compressedStream = new MemoryStream(data)) 
    using(var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress)) 
    using (var resultStream = new MemoryStream()) 
    { ... } 
} 

[편집 : 업데이트 다시 코멘트] 다시하지 usingMemoryStream 같은 -이 울타리의 양쪽에 투표를 많이, 항상 재미 하나입니다하지만 ultimatey ...

(수사학 - 우리 모두는 답을 알고 있습니다 ...) MemoryStream은 어떻게 구현 되었습니까? 그것은 byte [] (.NET 소유)입니까? 메모리 맵 파일 (OS 소유)입니까?

using이 아닌 이유는 내부 구현 세부 정보를 공개 API에 대해 코딩하는 방식이 바뀌었기 때문입니다. 즉, 캡슐화의 법칙을 어겼습니다. 공개 API에 따르면 : 나는 IDisposable입니다. 너는 나를 "소유"한다. 그러므로, 당신이 끝날 때 Dispose() 나에게 당신의 직업입니다.

+0

와우, 그것은 매력처럼 작동했습니다. 그것은 흥미로운데 왜냐하면 나는 Close()가 내부 메모리에 필요하다고 생각하지 않았기 때문에 윈도우 리소스가 관련되어 있지 않기 때문에 (흥미로운 것은 사용하는 블록에 대해 동일하게 간다 - 그것들이 없으면 클리너 만 사용했다) –

+0

Close()는 해제에 관한 것이 아니다. 여기에 Windows 리소스가 있습니다. GZip은 데이터의 끝 부분에 바닥 글이 필요하고 Close()는 GZipStream에 데이터 쓰기가 끝났음을 알리고 바닥 글을 작성해야합니다. – stevemegson

+0

올바른 구현 방법을 구현 세부 사항에서 정의하는 것이 맞을 수도 있습니다. 그러나 요즘 Microsoft는 처분 가능한 패턴을 많이 구현하고 있습니다 (처분 할 수없는 객체는 제외). –

3

또한 System.IO.Compression의 DeflateStream은 가장 효율적인 수축 알고리즘을 구현하지 않습니다. 원하는 경우 BCL GZipStream 및 DeflateStream 대신 사용할 수 있습니다. 이 기능은 내장 된 {Deflate, GZip} 스트림보다 성능이 우수한 zlib 코드 기반의 완전 관리 라이브러리로 구현됩니다. [그러나 여전히 스트림을 닫아서 전체 바이트 스트림을 가져와야합니다. ]

이러한 스트림 클래스는 DotNetZip 배포판 http://DotNetZip.codeplex.com/에서 사용할 수있는 DotNetZlib 어셈블리에서 제공됩니다.

+1

당신은 기뻐할 것이다. .NET 4.5가 zlib 알고리즘으로 BCL에 포함되어 있음을 알게되었습니다 (기존 압축 된 데이터에 대한 하위 호환성 포함). 자세한 내용은 여기를 참조하십시오. http://msdn.microsoft.com/en-us/magazine/jj133817.aspx – pattermeister

+1

Terrific! 너무 오래 걸렸지 만, 드디어 거기에 왔기 때문에 기쁩니다! – Cheeso

관련 문제