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

在每个请求的方法可以拿到 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中$forceUpdate()的使用

    刷新数组的作用 this.$forceUpdate(); 具体请看:vue中$forceUpdate()的使用 - 简书 (jianshu.com)

  2. KingbaseES V8R6 集群中复制槽非活跃状态的可能原因

    背景 此问题环境是一主五备物理集群,其中node1是主节点,node2,3是集群同步节点,node4,5是集群异地异步节点,由于异地和主节点不同网段,网速非常慢. kdts-plus工具纯迁数据,每分 ...

  3. java实战字符串4:寻找最长的元音子串的长度

    题目描述 定义:当一个字符串只有元音字母(aeiouAEIOU)组成,称为元音字符串.现给定一个字符串,请找出其中最长的元音字符子串,并返回其长度:如果找不到,则返回0. 子串:字符串中任意个连续的字 ...

  4. 基于 alientek rv1126 快速启动调试那的写坑

    基于 alientek rv1126 快速启动调试那的写坑 1. sdk 编制准备工作 1.1 编译配置修改 首先拿到 sdk 通过修改一下相关配置 1.1.1修改DDR 配置 cd /home/al ...

  5. #线性筛,斐波那契数列,GCD#BZOJ 2813 奇妙的Fibonacci

    题目 有一个斐波那契数列,满足 \[F_n=\begin{cases}1\qquad (n==1)\\1\qquad (n==2)\\F_{n-1}+F_{n-2}\qquad (n>2)\en ...

  6. #整体二分,树状数组#洛谷 3332 [ZJOI2013]K大数查询

    题目 分析 虽然树套树也可以做,这里考虑整体二分, 对于二分的答案\(mid\),1操作实际上就是如果\(c>mid\)就给区间整体加1, 2操作即询问区间和是否超过\(k\),如果超过\(k\ ...

  7. C# 字符串操作指南:长度、连接、插值、特殊字符和实用方法

    字符串用于存储文本.一个字符串变量包含由双引号括起的字符集合 示例: // 创建一个string类型的变量并赋予一个值 string greeting = "Hello"; 如果需 ...

  8. MogDB/openGauss 开机自启动

    MogDB/openGauss 开机自启动 在 centos7.6 操作系统上设置 MogDB/openGauss 开机自启动,我们先来了解一下自定义服务的配置文件组成部分,共分为[Unit].[Se ...

  9. openGauss共享存储对接Ceph-单机openGauss-Ceph zhangxb2023-02-18

    openGauss + DSS + Ceph 部署操作步骤 本文档介绍单机版 openGauss+DSS+Ceph 集群部署方式.后续提供主备下的步骤. 服务器: Hostname IP 系统 规格 ...

  10. 重新点亮linux 命令树————压缩和解压缩[四]

    前言 简单整理一下压缩和解压缩. 正文 在windows 中我们使用压缩和解压缩一般是7z这个压缩和解压软件,但是在linux中压缩和解压是两个不同的软件. 在最早的linux 备份介质是磁带,使用的 ...