我试图理解为什么我的代码没有按照需要执行。它创建一个GZipStream,然后将对象保存为我的硬盘驱动器上的压缩文件,但保存的文件总是0字节。
现在我知道如何save a file using GZipStream,但是,我的问题不是如何做到这一点。我的问题纯粹是为什么这段代码可以节省0个字节(或者为什么FileStream可以工作而内存不存在)。
private void BegingCompression()
{
var bytes = File.ReadAllBytes(this.fileName);
using (MemoryStream ms = new MemoryStream(bytes))
{
ms.ReadByte();
using (FileStream fs =new FileStream(this.newFileName, FileMode.CreateNew))
using (GZipStream zipStream = new GZipStream(ms, CompressionMode.Compress, false))
{
zipStream.Write(bytes, 0, bytes.Length);
}
}
}
关于源代码,this.fileName = c:\Audio.wav
和newFileName
是c:\Audio.wav.gz
(但也尝试了c:\audio.gz
)
答案 0 :(得分:14)
bytes
已经有要压缩的数据。 ms.ReadByte()
。 zipStream
时,应使用输出文件流。试试这个:
var bytes = File.ReadAllBytes(this.fileName);
using (FileStream fs =new FileStream(this.newFileName, FileMode.CreateNew))
using (GZipStream zipStream = new GZipStream(fs, CompressionMode.Compress, false))
{
zipStream.Write(bytes, 0, bytes.Length);
}
修改强>
原始代码会创建一个零长度文件,因为您不会写入文件流。
答案 1 :(得分:9)
当您使用GzipStream
命名空间中的DeflateStream
或System.IO.Compression
时,您在构造函数中提供的Stream
将被写入在解压缩中压缩和从读取。
由于您在此尝试压缩数据,因此使用MemoryStream
不正确,因为您没有尝试压缩它,而是将其用作数据源。因此,MemoryStream
应该是输入Stream
,而FileStream
是您的输出。
我强烈建议您使用MemoryStream
作为原始byte[]
的数据源,因为Stream
具有更多功能和应用(FileStream
,NetworkStream
,CryptoStream
等。)
以下是使用async
/ await
模式的一些示例:
public static async Task CompressToFileAsync(byte[] buffer,
string outputFile)
{
using (var inputStream = new MemoryStream(buffer))
await CompressToFileAsync(inputStream, outputFile);
}
public static async Task CompressToFileAsync(Stream inputStream,
string outputFile)
{
using (var outputStream = File.Create(outputFile))
using (var gzip = new GZipStream(outputStream, CompressionMode.Compress))
{
await inputStream.CopyToAsync(gzip);
gzip.Close();
}
}
public static async Task<MemoryStream> DecompressFromFileAsync(string inputFile)
{
var outputStream = new MemoryStream();
using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.Read))
using (var gzip = new GZipStream(inputStream, CompressionMode.Decompress))
{
await gzip.CopyToAsync(outputStream);
gzip.Close();
inputStream.Close();
// After writing to the MemoryStream, the position will be the size
// of the decompressed file, we should reset it back to zero before returning.
outputStream.Position = 0;
return outputStream;
}
}
注意:在关闭输入或输出 GzipStream.Close()
之前,请务必致电Stream
。它在关闭/处理时执行一些最终缓冲区刷新,如果输入或输出先关闭,它会在尝试执行此操作时抛出异常。 (这也适用于DeflateStream
)
答案 2 :(得分:3)
why FileStream works and memory doesn't
因为MemoryStream的后备存储是你的RAM内存,而不是硬盘。因此,当您将MemoryStream
对象传递给GZipStream
构造函数时,gzip将只在RAM中。
使用此代码:
using (FileStream fs =new FileStream(this.newFileName, FileMode.CreateNew))
您正在创建新的FileStream,但您没有使用它。要使用此FIleStream存储gzip,您需要将其传递给GZipStream
构造函数,以使其支持存储为硬盘驱动器。
答案 3 :(得分:2)
我使用此类进行压缩/解压缩:
internal class GZipProcessor : IZipProcessor
{
public 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 byte[] Decompress(byte[] data)
{
using (var compressedStream = new MemoryStream(data))
{
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
{
using (var resultStream = new MemoryStream())
{
zipStream.CopyTo(resultStream);
return resultStream.ToArray();
}
}
}
}
}
我如何使用它:
public void Compress(string inputPath, string outputPath)
{
byte[] originalBytes = File.ReadAllBytes(inputPath);
byte[] zippedBytes = base.ZipProcessor.Compress(originalBytes);
File.WriteAllBytes(outputPath, zippedBytes);
}
public void Decompress(string inputPath, string outputPath)
{
byte[] zippedBytes = File.ReadAllBytes(inputPath);
byte[] originalBytes = base.ZipProcessor.Decompress(zippedBytes);
File.WriteAllBytes(outputPath, originalBytes);
}
我还有一个代码更复杂的github repository