首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GZipStream在dotNET C#中的正确使用方法

GZipStream在dotNET C#中的正确使用方法
EN

Stack Overflow用户
提问于 2016-01-03 08:21:44
回答 2查看 4.3K关注 0票数 2

目前,我正在使用GZipStream 3.5使用.net。下面列出了两种方法。作为输入文件,我使用文本文件,其中包含字符's‘。文件大小为2MB。如果我使用.net 4.5,这段代码工作得很好,但是在使用.net 3.5时,经过压缩和解压缩,我得到了大小为435‘t的文件,这当然与源文件不一样。如果我试图通过WinRAR解压缩文件,它看起来也不错(与源文件相同)。如果我尝试使用GZipStream从.net4.5解压缩文件(通过GZipStream从.net 3.5压缩文件),结果会很糟糕。

UPD:通常,我确实需要将文件作为几个单独的gzip块来读取,在本例中,所有复制文件的字节都是在Read()方法的一个调用下读取的,所以我仍然不明白为什么解压缩不能工作。

代码语言:javascript
复制
    public void CompressFile()
    {
        string fileIn = @"D:\sin2.txt";
        string fileOut = @"D:\sin2.txt.pgz";

        using (var fout = File.Create(fileOut))
        {
            using (var fin = File.OpenRead(fileIn))
            {
                using (var zip = new GZipStream(fout, CompressionMode.Compress))
                {
                    var buffer = new byte[1024 * 1024 * 10];
                    int n = fin.Read(buffer, 0, buffer.Length);
                    zip.Write(buffer, 0, n);
                }
            }
        }
    }
    public void DecompressFile()
    {
        string fileIn = @"D:\sin2.txt.pgz";
        string fileOut = @"D:\sin2.1.txt";

        using (var fsout = File.Create(fileOut))
        {
            using (var fsIn = File.OpenRead(fileIn))
            {
                var buffer = new byte[1024 * 1024 * 10];
                int n;
                while ((n = fsIn.Read(buffer, 0, buffer.Length)) > 0)
                {
                    using (var ms = new MemoryStream(buffer, 0, n))
                    {
                        using (var zip = new GZipStream(ms, CompressionMode.Decompress))
                        {
                            int nRead = zip.Read(buffer, 0, buffer.Length);
                            fsout.Write(buffer, 0, nRead);
                        }
                    }
                }
            }
        }
    }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-01-03 08:35:43

您试图将每个“块”解压缩,就好像它是一个单独的gzip文件一样。不要那样做--只需在循环中从GZipStream中读取:

代码语言:javascript
复制
using (var fsout = File.Create(fileOut))
{
    using (var fsIn = File.OpenRead(fileIn))
    {
        using (var zip = new GZipStream(fsIn, CompressionMode.Decompress))
        {
            var buffer = new byte[1024 * 32];
            int bytesRead;

            while ((bytesRead = zip.Read(buffer, 0, buffer.Length)) > 0)
            {
                fsout.Write(buffer, 0, bytesRead);
            }
        }
    }
}

请注意,压缩代码应该看起来类似,在循环中读取,而不是假设对Read的单个调用将读取所有数据。

(就我个人而言,我会跳过fsIn,只使用new GZipStream(File.OpenRead(fileIn)),但这只是个人偏好。)

票数 3
EN

Stack Overflow用户

发布于 2016-01-03 09:02:17

首先,正如@Jon所提到的,您没有正确地使用Stream.Read方法。不管您的缓冲区是否足够大,流返回的字节比请求的要少,而零表示不多,因此应该始终在循环中执行从流的读取。

但是,解压缩代码中的主要问题是共享缓冲区的方式。您将输入读入缓冲区,而不是将其包装在MemoryStream中(请注意,所使用的构造函数并不复制传递的数组,而是实际上将其设置为内部缓冲区),然后尝试同时读取和写入该缓冲区。考虑到解压缩比读取更快地写入数据,您的代码竟然可以工作。

正确的实现非常简单。

代码语言:javascript
复制
static void CompressFile()
{
    string fileIn = @"D:\sin2.txt";
    string fileOut = @"D:\sin2.txt.pgz";
    using (var input = File.OpenRead(fileIn))
    using (var output = new GZipStream(File.Create(fileOut), CompressionMode.Compress))
        Write(input, output);
}

static void DecompressFile()
{
    string fileIn = @"D:\sin2.txt.pgz";
    string fileOut = @"D:\sin2.1.txt";
    using (var input = new GZipStream(File.OpenRead(fileIn), CompressionMode.Decompress))
    using (var output = File.Create(fileOut))
        Write(input, output);
}

static void Write(Stream input, Stream output, int bufferSize = 10 * 1024 * 1024)
{
    var buffer = new byte[bufferSize];
    for (int readCount; (readCount = input.Read(buffer, 0, buffer.Length)) > 0;)
        output.Write(buffer, 0, readCount);
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34574637

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档