.Net Framework 2.0中的Compression功能

以前做项目的时候,需要提供文件压缩功能。当时是使用了一个开源的类库,名为ZipLib,使用起来还是很方便的。我还在自己的英文博客上post了一篇文章《ZipLib Works Well! 》也许是看到了这个功能的必要性,在.Net 2.0中,微软在System.IO中新增了System.IO.Compression命名空间,提供了压缩功能的相关类GZipStream。

这个类的使用与一般的文件流使用差不多。我没有分析其内部实现,但猜测应该还是采用Decorator模式对Stream进行了装饰,从中应用了Compression算法。它通过Write()方法,将buffer里面的内容写到另一个文件流中,例如源文件为sourceFile,压缩后的文件为targetFile,则方法为:
byte[] buffer = null;
FileStream sourceStream 
= null;
FileStream targetStream 
= null;
GZipStream compressedStream 
= null;

sourceStream 
= new FileStream(sourceFile,FileMode.Open,FileAccess.Read,FileShare.Read);
buffer 
= new byte[sourceStream.Length];
sourceStream.Read(buffer,
0,buffer.Length);

targetStream 
= new FileStream(targetFile,FileMode.OpenOrCreate,FileAccess.Write);
//将CompressedStream指向targetStream;
compressedStream = new GZipStream(targetStream,CompressionMode.Compress,true);
compressStream.Write(buffer,
0,buffer.Length);

在使用GZipStream时,需要添加引用:

using System.IO;
using System.IO.Compression;

解压缩与前面的方法差不多,仍然使用GZipStream文件流:

// Read in the compressed source stream
sourceStream = new FileStream ( sourceFile, FileMode.Open );

// Create a compression stream pointing to the destiantion stream
decompressedStream = new GZipStream ( sourceStream, CompressionMode.Decompress, true );

// Read the footer to determine the length of the destiantion file
quartetBuffer = new byte[4];
int position = (int)sourceStream.Length - 4;
sourceStream.Position 
= position;
sourceStream.Read ( quartetBuffer, 
04 );
sourceStream.Position 
= 0;
int checkLength = BitConverter.ToInt32 ( quartetBuffer, 0 );

byte[] buffer = new byte[checkLength + 100];

int offset = 0;
int total = 0;

// Read the compressed data into the buffer
while ( true )
{
             
int bytesRead = decompressedStream.Read ( buffer, offset, 100 );

             
if ( bytesRead == 0 )
                        
break;

             offset 
+= bytesRead;
             total 
+= bytesRead;
  }


  
// Now write everything to the destination file
  destinationStream = new FileStream ( destinationFile, FileMode.Create );
  destinationStream.Write ( buffer, 
0, total );

  
// and flush everyhting to clean out the buffer
  destinationStream.Flush ( );

.Net 2.0中除了提供GZipStream外,还提供了DeflateStream类,它仍然具有压缩的功能,只是采用的压缩算法不同而已。

using System;
using System.IO;
using System.IO.Compression;

public class DeflateTest
{
    
public static int ReadAllBytesFromStream(Stream stream, byte[] buffer) 
    
{
    
// Use this method is used to read all bytes from a stream.
    int offset = 0;
    
int totalCount = 0;
        
while (true
        
{
        
int bytesRead = stream.Read(buffer, offset, 100); 
            
if ( bytesRead == 0
            
{
            
break
            }

    offset 
+= bytesRead;
    totalCount 
+= bytesRead; 
        }

    
return totalCount;
    }
 

    
public static bool CompareData(byte[] buf1, int len1, byte[] buf2, int len2) 
    
{
        
// Use this method to compare data from two different buffers.
        if (len1 != len2) 
        

        Console.WriteLine(
"Number of bytes in two buffer are different {0}:{1}", len1, len2);
        
return false;
        }


        
for ( int i= 0; i< len1; i++
        
{
            
if ( buf1[i] != buf2[i]) 
            
{
            Console.WriteLine(
"byte {0} is different {1}|{2}", i, buf1[i], buf2[i]);
            
return false;
            }

        }

    Console.WriteLine(
"All bytes compare.");
    
return true
    }


    
public static void DeflateCompressDecompress(string filename)
    
{
    Console.WriteLine(
"Test compression and decompression on file {0}", filename);
    FileStream infile;
        
try
        
{
        
// Open the file as a FileStream object.
        infile = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
        
byte[] buffer = new byte[infile.Length];
        
// Read the file to ensure it is readable.
        int count = infile.Read(buffer, 0, buffer.Length);
            
if ( count != buffer.Length) 
            
{
            infile.Close();
            Console.WriteLine(
"Test Failed: Unable to read data from file"); 
            
return;
            }

        infile.Close();
        MemoryStream ms 
= new MemoryStream();
        
// Use the newly created memory stream for the compressed data.
        DeflateStream compressedzipStream = new DeflateStream(ms , CompressionMode.Compress, true);
        Console.WriteLine(
"Compression");
        compressedzipStream.Write(buffer, 
0, buffer.Length);
        
// Close the stream.
        compressedzipStream.Close();
        Console.WriteLine(
"Original size: {0}, Compressed size: {1}", buffer.Length, ms.Length);

        
// Reset the memory stream position to begin decompression.
        ms.Position = 0;
        DeflateStream zipStream 
= new DeflateStream(ms, CompressionMode.Decompress);
        Console.WriteLine(
"Decompression");
        
byte[] decompressedBuffer = new byte[buffer.Length + 100];
        
// Use the ReadAllBytesFromStream to read the stream.
        int totalCount = DeflateTest.ReadAllBytesFromStream(zipStream, decompressedBuffer);
        Console.WriteLine(
"Decompressed {0} bytes", totalCount);

        
if!DeflateTest.CompareData(buffer, buffer.Length, decompressedBuffer, totalCount) ) 
        
{
        Console.WriteLine(
"Error. The two buffers did not compare.");
        }

    zipStream.Close(); 
        }
 // end try
        catch (InvalidDataException)
        
{
            Console.WriteLine(
"Error: The file being read contains invalid data.");
        }

        
catch (FileNotFoundException)
        
{
            Console.WriteLine(
"Error:The file specified was not found.");
        }

        
catch (ArgumentException)
        
{
            Console.WriteLine(
"Error: path is a zero-length string, contains only white space, or contains one or more invalid characters");
        }

        
catch (PathTooLongException)
        
{
            Console.WriteLine(
"Error: The specified path, file name, or both exceed the system-defined maximum length. For example, on Windows-based platforms, paths must be less than 248 characters, and file names must be less than 260 characters.");
        }

        
catch (DirectoryNotFoundException)
        
{
            Console.WriteLine(
"Error: The specified path is invalid, such as being on an unmapped drive.");
        }

        
catch (IOException)
        
{
            Console.WriteLine(
"Error: An I/O error occurred while opening the file.");
        }

        
catch (UnauthorizedAccessException)
        
{
            Console.WriteLine(
"Error: path specified a file that is read-only, the path is a directory, or caller does not have the required permissions.");
        }

        
catch (IndexOutOfRangeException)
        
{
            Console.WriteLine(
"Error: You must provide parameters for MyGZIP.");
        }

    }

    
public static void Main(string[] args)
    
{
        
string usageText = "Usage: DeflateTest <inputfilename>";
        
//If no file name is specified, write usage text.
        if (args.Length == 0)
        
{
            Console.WriteLine(usageText);
        }

        
else
        
{
            
if (File.Exists(args[0]))
                DeflateCompressDecompress(args[
0]);
        }

    }

}


 


微软在加入GZipSream和DeflateStream后,使得.Net对文件流的支持更加丰富。我们也可以直接利用.Net Framework 2.0写出自己的压缩程序了。

本文的代码部分来自Visual Studio 2005 101Sample C#.
posted @ 2005-08-23 16:50  张逸  阅读(4224)  评论(7编辑  收藏  举报