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

在每个请求的方法可以拿到 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. vivado2019操作之约束文件

    Vivado2019的约束文件 1. 约束文件 vivado的约束文件是以xdc为后缀的.该文件具有时序约束和管脚约束的作用.该文件可以自己创建,也可以通过内置工具创建. 2.基本操作 (1)使用内部 ...

  2. 初学STM32 CAN通信(三)

    1. stm32 CAN通信标准库函数 //CAN通信初始化函数 uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct ...

  3. .NET Core WebApi 多语言本地化,动态切换多语言

    .NET Core WebApi 多语言本地化,动态切换多语言 原生的.net core webapi 动态多语言本地话 具体更多详细内容,可以参考官方文档 首先看效果图 整体项目结构图 开始前需要讲 ...

  4. 实用 Linux 命令 Windos 命令 实例演示 持续更新中

    实用 Linux 命令 Windos 命令 实例演示 持续更新中 目录 实用 Linux 命令 Windos 命令 实例演示 持续更新中 Linux 命令 [Command [options] [lo ...

  5. #构造#洛谷 6470 [COCI2008-2009#6]CUSKIJA

    题目 给定一个长度为 \(n\) 的序列 \(a\),请将其重新排序, 新序列中任意相邻两个数之和都不能被 \(3\) 整除. 分析 分类讨论,如果只有3的倍数多于1个无解 没有 \(3k+1\) 或 ...

  6. JDK 14的新特性:文本块Text Blocks

    目录 举个例子 Indentation编排 Escaping转义 formatted格式化 总结 说起来,Text Blocks是在JDK13中以第一次预览版本引入的.现在在JDK14中是第二次预览版 ...

  7. 在DAYU200上实现OpenHarmony跳转拨号界面

    一.简介 日常生活中,打电话是最常见的交流方式之一,那么如何在OpenAtom OpenHarmony(简称"OpenHarmony")中进行电话服务相关的开发呢?今天我们可以一起 ...

  8. 品质影音体验,畅享娱乐生活丨HMS Core.Sparkle影音娱乐创新线上沙龙报名启动

    从全民娱乐到全民创作,音视频.直播已成为文娱市场中最为活跃的内容形态,用户在享受视听娱乐的同时,也更期待通过这些平台来表达自己. 面对用户个性化需求的增加,影音娱乐应用开发者和内容平台,该如何通过技术 ...

  9. openGauss每日一练第三天

    openGauss 每日一练第三天 本文出处:https://www.modb.pro/db/193083 学习目标 学习 openGauss 创建数据库.修改数据库属性和删除数据库 课后作业 1.分 ...

  10. 【鸿蒙千帆起】《钢岚》成为首款基于HarmonyOS NEXT开发的战棋新游

      近日,紫龙游戏旗下BlackJack工作室全新战棋旗舰作品<钢岚>在华为游戏中心首发上线,并宣布<钢岚>完成鸿蒙原生应用开发,成为基于HarmonyOS NEXT开发的首款 ...