• 使用GZipStream压缩和解压文件


    最近做了一个用.NET里的GZipStream压缩解压缩gzip文件的小程序。
    GZipStream在System.IO.Compression底下,使用起来也很简单。虽然GZipStream是Stream类的一个下级类,但它只相当于一个转换器。在两个Stream之间将数据转换成为压缩或解压缩数据。
    下面是一个简单的例子:
    static void Main(string[] args)
    {
        string inputFileName = @"TestFile/Test.doc";
        string outputFileName = @"TestFile/Test.doc.gz";
       
        // 输入输出数据流
        FileStream inputStream =
            new FileStream(inputFileName, FileMode.Open, FileAccess.Read);
        FileStream outputStream =
            new FileStream(outputFileName, FileMode.Create, FileAccess.Write);
        // 把数据读到一个字节类型的数组里
        byte[] buffer = new byte[inputStream.Length];
        inputStream.Read(buffer, 0, buffer.Length);
       
        GZipStream compressionStream =
            new GZipStream(outputStream, CompressionMode.Compress);
       
        // 把数组里的数据通过GZipStream写入到输出数据流
        compressionStream.Write(buffer, 0, buffer.Length);
        compressionStream.Close();
       
        inputStream.Close();
        outputFileName.Close();
        Console.WriteLine("Finished");
        Console.ReadLine();
    }
    以上这个例子已经可以满足基本的压缩需求,但他还有一个很大的缺点,那就是必须把全部文件都读到内存里(也就是那个字节型的数组),然后才能进行压缩。当压缩很大的文件的时候系统性能会受到很大的影响,甚至可能使系统崩溃。
    所以我给他改进了一下,让他一次只读取和压缩文件的一部份:
    static void Main(string[] args)
    {
        string inputFileName = @"TestFile/Test.doc";
        string outputFileName = @"TestFile/Test.doc.gz";
       
        FileStream inputStream =
            new FileStream(inputFileName, FileMode.Open, FileAccess.Read);
        FileStream outputStream =
            new FileStream(outputFileName, FileMode.Create, FileAccess.Write);
        // 决定一次读取数剧的大小,这里是8KB
        int bufferSize = 8192;
        int bytesRead = 0;
        byte[] buffer = new byte[bufferSize];
        GZipStream compressionStream =
            new GZipStream(outputStream, CompressionMode.Compress);
        // bytesRead返回每次读了多少数据,如果等于0就表示已经没有数据
        // 可以读了
        while ( (bytesRead = inputStream.Read(buffer, 0, bufferSize)) > 0)
        {
            // 把读到数组中的数据通过GZipStream写入到输出数据流
            compressionStream.Write(buffer, 0, bytesRead);
        }
        compressionStream.Close();
       
        inputStream.Close();
        outputStream.Close();
        Console.WriteLine("Finished");
        Console.ReadLine();
    }
    好子,现在可以解决刚才提到的性能问题了。
    解压缩文件和压缩文件基本一样,只不过这次GZipStream是要从已经压缩了文件中读取数据并解压缩,然后把解压后的数据写入到另一个文件,所以这次GZipStream是在读,看一面的例子:
    static void Main(string[] args)
    {
        string inputFileName = @"TestFile/Test.doc.gz";
        string outputFileName = @"TestFile/Test_unzipped.doc";
       
        FileStream inputStream =
            new FileStream(inputFileName, FileMode.Open, FileAccess.Read);
        FileStream outputStream =
            new FileStream(outputFileName, FileMode.Create, FileAccess.Write);
       
        int bufferSize = 8192;
        int bytesRead = 0;
        byte[] buffer = new byte[bufferSize];
        GZipStream decompressionStream =
            new GZipStream(inputStream, CompressionMode.Decompress);
        // 把压缩了的数据通过GZipStream解压缩后再读出来
        // 读出来的数据就存在数组里
        while ( (bytesRead = decompressionStream.Read(buffer, 0, bufferSize)) > 0)
        {
            // 把解压后的数据写入到输出数据流
            outputStream.Write(buffer, 0, bytesRead);
        }
        decompressionStream.Close();
       
        inputStream.Close();
        outputStream.Close();
        Console.WriteLine("Finished");
        Console.ReadLine();
    }
    我把刚才写的程序优化了一下,制作了一个比较容易使用的GZip工具 -- GZipTool,下面是这个工具支持的几个方法:
    // 压缩指定文件,跟踪压缩进度,设置缓冲大小
    GZipTool.Compress(string inputFileName, ProgressHandler handler, int bufferSize);
    示例:
    static void Main(string[] args)
    {
        string inputFileName = @"TestFile/Test.doc";
       
        // 压缩指定文件,显示进度,并设定一次压缩数据的大小
        GZipTool.Compress(inputFileName,
            new GZipTool.ProgressHandler(_progress), 20480);
        Console.WriteLine("Finished");
        Console.ReadLine();
    }
    // 显示进度数据
    private static void _progress(long totalBytesProcessed, long totalBytes)
    {
        Console.WriteLine(
            (
            (double)totalBytesProcessed / (double) totalBytes).ToString("P")        );
    }
    GZipTool还支持把数据直接压缩成为数据流,可以在网络传输等不需要文件系统的环境下使用。
    // 把输入数据流压缩,并把压缩后的数据包在一个MemoryStream里返回
    MemoryStream GZipTool.Compress(Stream inputStream)
    GZipTool在解压缩文件的时候也支持进度跟踪
    // 解压指定文件并给以指定名称,跟踪压缩进度,设置缓冲大小
    GZipTool.Decompress(string gZipFileName,     string outputFileName,
                ProgressHandler handler, int bufferSize)
    GZipTool还支持读取gzip文件的描述信息,包括原始文件大小等
    // 把指定gzip文件的描述信息读到一个GZipFileInfo结构里
    GZipFileInfo GZipTool.GetFileInfo(string gZipFileName)
    示例:
    static void Main(string[] args)
    {
        string inputFileName = @"TestFile/Test.doc.gz";
       
        GZipFileInfo fileInfo = GZipTool.GetFileInfo(inputFileName);
        Console.WriteLine("GZip File Name: {0}", inputFileName);
        // 输出原始文件大小
        Console.WriteLine("Original File Size: {0}", fileInfo.OriginalFileSize);
        Console.WriteLine("Finished");
        Console.ReadLine();
    }
  • 相关阅读:
    C#基础之事件
    C#中IQueryable和IEnumerable的区别(2)
    读取不到appsettings.json的值
    【PHP】 延时跳转
    【canvas】 绘制七巧板
    小程序项目编译失败问提解决
    windows下安装node.js
    deskgenius分区失败,分区消失,解决的过程
    IOS:重写UISlider大小解决UISlider滑动不灵敏的问题
    IOS:reason: 'invalid nib registered for identifier (PhotoCellID)
  • 原文地址:https://www.cnblogs.com/topguntopgun/p/3987938.html
Copyright © 2020-2023  润新知