我是否可以在磁盘上获取GZipStream
文件,而无需将整个压缩内容写入临时存储空间?我目前正在磁盘上使用临时文件,以避免在非常大的文件上使用MemoryStream
可能导致内存耗尽(这很好)。
public void UploadFile(string filename)
{
using (var temporaryFileStream = File.Open("tempfile.tmp", FileMode.CreateNew, FileAccess.ReadWrite))
{
using (var fileStream = File.OpenRead(filename))
using (var compressedStream = new GZipStream(temporaryFileStream, CompressionMode.Compress, true))
{
fileStream.CopyTo(compressedStream);
}
temporaryFileStream.Position = 0;
Uploader.Upload(temporaryFileStream);
}
}
我想要做的是通过创建GZipStream
来消除临时存储,并且只有当Uploader类从它请求字节时才从原始文件中读取它。这样的事情可能吗?如何构建这样的实现?
请注意,Upload
是一个带有签名static void Upload(Stream stream)
的静态方法。
修改:如果完整代码有用,则代码为here。我希望我已经在上面的示例中包含了所有相关的上下文。
答案 0 :(得分:5)
是的,这是可能的,但不容易使用任何标准的.NET流类。当我需要做这样的事情时,我创建了一个new type of stream。
它基本上是一个循环缓冲区,允许一个生产者(作家)和一个消费者(读者)。它非常易于使用。让我举一个例子。与此同时,您可以调整文章中的示例。
后来:这是一个应该接近你所要求的例子。
using (var pcStream = new ProducerConsumerStream(BufferSize))
{
// start upload in a thread
var uploadThread = new Thread(UploadThreadProc(pcStream));
uploadThread.Start();
// Open the input file and attach the gzip stream to the pcStream
using (var inputFile = File.OpenRead("inputFilename"))
{
// create gzip stream
using (var gz = new GZipStream(pcStream, CompressionMode.Compress, true))
{
var bytesRead = 0;
var buff = new byte[65536]; // 64K buffer
while ((bytesRead = inputFile.Read(buff, 0, buff.Length)) != 0)
{
gz.Write(buff, 0, bytesRead);
}
}
}
// The entire file has been compressed and copied to the buffer.
// Mark the stream as "input complete".
pcStream.CompleteAdding();
// wait for the upload thread to complete.
uploadThread.Join();
// It's very important that you don't close the pcStream before
// the uploader is done!
}
上传线程应该非常简单:
void UploadThreadProc(object state)
{
var pcStream = (ProducerConsumerStream)state;
Uploader.Upload(pcStream);
}
当然,您可以将生产者放在后台线程上,并在主线程上完成上传。或者将它们都放在后台线程上。我不熟悉你的上传者的语义,所以我会把这个决定留给你。