本文主要是告诉大家一个省内存的方法,将整个文件夹的内容作为一个压缩包输出,但是实际上没有申请那么多的内存,也不需要升级创建一个压缩包文件。原理是通过逐个读文件然后按照压缩包格式输出

在每个请求的方法可以拿到 HttpContext 属性,通过这个属性拿到 Response 属性,在这里可以使用 BodyWriter 属性,在这个属性里面写入的内容将会被客户端下载

而这个属性可以作为 Stream 请看下面代码

     using var stream = HttpContext.Response.BodyWriter.AsStream();

在 .NET 中可以通过 ZipArchive 将一个文件夹的文件按照压缩文件格式写入,还可以设置压缩的压缩率等,可以设置文件所在文件夹的路径

通过在这个 stream 创建一个 ZipArchive 类,然后在这个类里面创建文件的方法就可以做到不断向客户端发送文件,发送的文件都在一个压缩包里面

        /// <summary>
/// 将一个文件夹的内容读取为 Stream 的压缩包
/// </summary>
/// <param name="directory"></param>
/// <param name="stream"></param>
public static async Task ReadDirectoryToZipStreamAsync(DirectoryInfo directory, Stream stream)
{
var fileList = directory.GetFiles(); using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create);
foreach (var file in fileList)
{
var relativePath = file.FullName.Replace(directory.FullName, "");
if (relativePath.StartsWith("\\") || relativePath.StartsWith("//"))
{
relativePath = relativePath.Substring(1);
} var zipArchiveEntry = zipArchive.CreateEntry(relativePath, CompressionLevel.NoCompression); using (var entryStream = zipArchiveEntry.Open())
{
using var toZipStream = file.OpenRead();
await toZipStream.CopyToAsync(stream);
} await stream.FlushAsync();
}
}

上面的代码可以让运行的程序不需要申请和需要传输一样大的内存空间,或者不需要先执行压缩放在本地文件,可以不断读取本地文件然后上传。读取本地文件等都通过 CopyToAsync 自动设置缓存大小。如果不放心 CopyToAsync 方法设置的缓存大小,可以通过重载的方法手动设置缓存的大小

      await toZipStream.CopyToAsync(stream, bufferSize: 100);

上面的代码设置了文件不要压缩,因为作为文件传输的时候,实际上我的业务是在内网传输,我的磁盘读取速度大概是 20M 一秒,而网络传输是 10M 一秒,也就是此时的压缩其实没什么意义,压缩减少的内容减少的传输时间就和压缩的时间差不多

如果小伙伴需要传输的时候压缩,请设置 zipArchive.CreateEntry 方法

当然此方法的缺点是,也许传输的时候服务器自己读取文件炸了,此时就会传输的文件不对,同时客户端不知道服务器传的对不对,因为压缩的大小没有告诉客户端。如果要告诉客户端压缩后的大小就需要先在服务器端进行压缩。本文的方法设置的是没有压缩率的压缩,大概的大小还可以告诉用户

此方法可以如何使用?在随意一个 Get 方法里面就可以通过 HttpContext 传入 Response 属性

在使用 BodyWriter 写入之前需要先设置 StatusCode 的值

            HttpContext.Response.StatusCode = StatusCodes.Status200OK;

            using var stream = HttpContext.Response.BodyWriter.AsStream();

假设需要返回的文件夹是 f:\lindexi\test\ 可以通过下面代码的方式将文件夹输出为压缩包

        [HttpGet]
[Route("{id}")]
public async Task Get([FromRoute] string id)
{
var folder = @"f:\lindexi\test\";
HttpContext.Response.StatusCode = StatusCodes.Status200OK; using var stream = HttpContext.Response.BodyWriter.AsStream(); await ReadDirectoryToZipStreamAsync(new DirectoryInfo(folder), stream);
}

本地我写了一个 PowerShell 脚本运行

For ($i=0; $i -le 100000; $i++)
{
(new-object System.Net.WebClient).DownloadFile("http://localhost:5000/File/doubi", "F:\lindexi\zip\2.zip")
}

本地运行这个脚本可以看到内存其实没有 GC 也没有溢出,我运行看到内存大概在 100M 左右

获取的时候会占用一些 CPU 资源,但是很省内存

如果小伙伴有更好的方法欢迎告诉我

ASP.NET Core 将文件夹内容输出为压缩包文件方法的更多相关文章

  1. 文件下载Controller,文件夹内容监听,文件上传,运行程序通过url实现文件下载

    文件下载Controller @RequestMapping("/fileDownLoad") public ResponseEntity<byte[]> fileDo ...

  2. Windows 下自动同步文件夹内容到另一个文件夹下

    实现windows 使用bat脚本文件,复制文件夹到另一个盘,参考如下代码:/y是可以不显示:提示你需要覆盖一个文件,如下图: bat文件内容为 @echo off echo "使用bat脚 ...

  3. 【linux】复制文件夹内容到另一个文件夹

    我一直觉得cp是个非常简单的指令.结果居然遇到坑了.记录一下. 文件夹1:test1/ 文件夹2:test2/ 目标:将test1/中的所有文件和目录拷贝到test2/中 正确指令: cp -rf t ...

  4. shell脚本复制文件夹内容到另外的文件夹,如果存在则自动备份

    有时我们需要将一个文件夹覆盖到我们的工作目录,但需要自动备份已经存在的文件,一个一个去备份太麻烦了,全部备份又没有必要.shell脚本可以很好滴完成这个任务.原文链接http://back.zhizh ...

  5. 取得文件夹内容信息(使用IShellFolder接口)

    翻译自MSDN 2005 -> Win32 和 COM 开发 -> User Interface -> Windows User Experience -> Windows S ...

  6. 读取同一文件夹下多个txt文件中的特定内容并做统计

    读取同一文件夹下多个txt文件中的特定内容并做统计 有网友在问,C#读取同一文件夹下多个txt文件中的特定内容,并把各个文本的数据做统计. 昨晚Insus.NET抽上些少时间,来实现此问题,加强自身的 ...

  7. PHP批量清空删除指定文件夹内容

    PHP批量清空删除指定文件夹内容: cleancache.php <?php // 清文件缓存 $dirs = array( realpath(dirname(__FILE__) . '/../ ...

  8. Path,Files巩固,题目:从键盘接收两个文件夹路径,把其中一个文件夹中(包含内容)拷贝到另一个文件夹中

    这个题目用传统的File,InputStream可以做,但是如果用Files,Path类做,虽然思路上会困难一些,但是代码简洁了很多,以下是代码: import java.io.IOException ...

  9. linux bash脚本把A和B文件中有相同ID的B文件的内容输出到文件C

    bash脚本把A和B文件中有相同ID的B文件的内容输出到文件C. Aid文件:ID001.1ID032.1ID090.10 Bfilt文件:XX XX XXX ID001.1 XXX999999999 ...

  10. 将CMD内的显示内容输出到txt文件

    将CMD内的显示内容输出到txt文件 xxxx -t >c:\test.txt        //xxxx为命令  如ping www.baidu.com //-t >c:\test.tx ...

随机推荐

  1. vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 一.是什么 权限是对特定资源的访问许可,所谓权限控制,也就是确保用户只能访问到被分配的资源 而前端权限归根结底是请求的发起权,请求的发起可 ...

  2. 记录--CSS 如何实现羽化效果?

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 最近碰到这样一个问题,在一张封面上直接显示书名,可能会存在书名看不太清楚的情况(容易受到背景干扰),如下 为了解决这个问题,设计师提了一个 ...

  3. C# OpenCv 证件照换底色

    using OpenCvSharp; using System; using System.Collections.Generic; using System.Linq; using System.T ...

  4. KingbaseES 复制冲突之锁类型冲突

    背景 昨天遇到客户现场的一个有关复制冲突的问题 备库报错:ERROR: canceling statement due to conflict with recovery,user was holdi ...

  5. KingbaseES Create Index Concurrently 过程探究

    前言: 我们知道Oracle 可以通过create index online 在线创建索引,而不影响其他会话修改数据,但Oracle 实际在online 创建索引的最后一步,实际还是需要进行锁升级,申 ...

  6. archlinux运行appimage

    1.cd进入appimage所在的目录 cd your_folder 2.赋予appimage运行权限 chmod +x your_file.appimage 3.运行appimage格式文件 ./y ...

  7. Scala 元祖Tuple

    1 package chapter07 2 3 object Test10_Tuple { 4 def main(args: Array[String]): Unit = { 5 // 1. 创建元组 ...

  8. Python---json数据格式详解

    什么是JSON JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度. 那么,JSON到底是什么? JSON就是一串字符串 ...

  9. Buffer 与 Mat 互转

    Linux系统做音视频开发,很多时候要用到opencv,就需要把图片Buffer数据转换成Mat对象来使用 Buffer 转 Mat Mat Buffer2Mat(unsigned char* buf ...

  10. 部署javaweb项目到阿里云ecs(centos7)

    阿里云文档 https://help.aliyun.com/document_detail/51376.html?spm=5176.12901015.0.i12901015.af8f525cCPi8Q ...