我是否可以在不写入中间临时存储的情况下获取文件的GZipStream?

 SH_ZTH_611_666_104_534 发布于 2023-01-08 21:35

我是否可以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).

编辑:完整的代码在这里,如果它是有用的.我希望我已经在上面的示例中包含了所有相关的上下文.

1 个回答
  • 是的,这是可能的,但不容易使用任何标准的.NET流类.当我需要做这样的事情时,我创建了一种新类型的流.

    它基本上是一个循环缓冲区,允许一个生产者(作家)和一个消费者(读者).它非常易于使用.让我举一个例子.在此期间,您可以调整文章中的示例.

    后来:这是一个应该接近你要求的例子.

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

    当然,您可以将生产者放在后台线程上,并在主线程上完成上传.或者将它们都放在后台线程上.我不熟悉你的上传者的语义,所以我会把这个决定留给你.

    2023-01-08 21:42 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有