Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/272.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在dotnetc中使用GZipStream的正确方法#_C#_.net_.net 3.5_Gzipstream - Fatal编程技术网

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

C# 在dotnetc中使用GZipStream的正确方法#,c#,.net,.net-3.5,gzipstream,C#,.net,.net 3.5,Gzipstream,目前我正在使用.NET3.5使用GZipStream。 我有下面列出的两种方法。作为输入文件,我使用由字符组成的文本文件。文件大小为2MB。如果我使用.NET4.5,这段代码可以很好地工作,但是使用.NET3.5,在压缩和解压缩后,我得到的文件大小为435KB,这当然与源文件不同。 如果我尝试通过WinRAR解压文件,看起来也不错(源文件也是如此)。 如果我尝试使用.net4.5中的GZipStream解压文件(通过.net3.5中的GZipStream压缩的文件),结果是不好的 UPD: 一般

目前我正在使用.NET3.5使用GZipStream。 我有下面列出的两种方法。作为输入文件,我使用由字符组成的文本文件。文件大小为2MB。如果我使用.NET4.5,这段代码可以很好地工作,但是使用.NET3.5,在压缩和解压缩后,我得到的文件大小为435KB,这当然与源文件不同。 如果我尝试通过WinRAR解压文件,看起来也不错(源文件也是如此)。 如果我尝试使用.net4.5中的GZipStream解压文件(通过.net3.5中的GZipStream压缩的文件),结果是不好的

UPD: 一般来说,我真的需要将文件作为几个单独的gzip块来读取,在这种情况下,所有压缩文件的字节都是在read()方法的一次调用中读取的,所以我仍然不理解为什么解压缩不起作用

    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);
                        }
                    }
                }
            }
        }
    }

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

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
,只使用
newgzipstream(File.OpenRead(fileIn))
,但这只是我个人的偏好。)

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

然而,解压代码中的主要问题是共享缓冲区的方式。您将输入读取到缓冲区中,然后将其包装到
MemoryStream
中(请注意,使用的构造函数不复制传递的数组,而是将其设置为内部缓冲区),然后您尝试同时读取和写入该缓冲区。考虑到解压缩写入数据比读取数据“更快”,您的代码能够正常工作是令人惊讶的

正确的实现非常简单

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);
}

嗯,你的代码很好用。但不管怎样,在我的代码中,我使用了一个足够大的块(10MB)一次性读取文件中的所有字节,所以你知道为什么它不工作吗?一般来说,我需要将压缩文件分块读取,因为我将源文件压缩了几个线程,因此我得到了一个头为10字节的文件和一系列压缩块,头为4字节,前缀为下一个块的长度。@Leo:你仍然假设,仅仅是因为你提供了足够大的缓冲区,它将在一次调用中读取所有内容。一般来说,流不是这样工作的-你不应该依赖于一个调用来读取整个文件。谢谢,据我所知,为了准确读取“count”字节,我需要执行以下操作:“int nRead=0;while(nRead!=count){nRead+=inputStream.Read(buffer,nRead,count-nRead);}“我说得对吗?在哪些情况下,Read可以返回小于count的nRead?”?(不包括达到EOF)。我想,如果文件是从网上下载的,但不确定这一点,可能会发生这种情况,也许还有其他可能cases@Leo:任何数量的箱子,真的。想象一下,如果您使用的是FileStream,但它是一个网络共享。。。这可能决定给你一些数据。如果解密只返回适当的块,那么它可能更容易实现。基本上,除非保证不会,否则不要认为它不会:)被发现了!我甚至没有注意到这一点。。。请注意,在.NET4中,
Stream
获得了一个
CopyTo
,就像您的
Write
方法一样。我个人使用了一种扩展方法(也称为
CopyTo
)来做同样的事情。。。虽然我不会选择10MB作为默认缓冲区大小。(我还强烈鼓励在使用指令、循环等时使用大括号……我见过太多由于缺少它们而导致的错误。)@JonSkeet你当然是对的。我使用了自定义名称和默认大小10MB来匹配操作码。关于大括号呢,我不在单个语句中使用大括号,但我明白你在说什么:)谢谢,我在这里的第一个错误是:“将它包装在MemoryStream中(请注意,使用的构造函数不复制传递的数组,而是将其设置为内部缓冲区)”为拷贝字节比特流添加新的缓冲区解决了这个问题,正如@JonSkeet所说的,第二个错误与使用来自MSDN的流有关,“在没有可用数据的情况下,实现将阻塞,直到至少可以读取一个字节的数据。”非常感谢,我会纠正我的错误,然后希望程序能正常运行。对不起,错误的引用我的意思是“一个实现可以自由返回比请求更少的字节,即使没有到达流的结尾。”