当前位置: 首页 > news >正文

gin框架实现大文件下载

在gin框架中实现大文件下载主要分为两个步骤:

  1. 将文件分块读取

由于大文件一次性读取会占用大量内存,容易导致内存溢出等问题,需要将文件分块读取,逐一发送给客户端。

在gin框架中,可以使用context.File方法向客户端发送文件,该方法需要传入文件路径和文件名。为了实现分块读取,我们可以使用os包中的File类型的Read()方法,该方法可以从文件中读取指定长度的数据。

以下是分块读取文件并发送给客户端的代码:

import ("os""strconv""github.com/gin-gonic/gin"
)
func DownloadFile(c *gin.Context) {filePath := "path/to/file"fileName := "file_name"file, err := os.Open(filePath)if err != nil {c.AbortWithError(404, err)return}defer file.Close()stat, err := file.Stat()if err != nil {c.AbortWithError(404, err)return}c.Writer.Header().Set("Content-Disposition", "attachment; filename="+fileName)c.Writer.Header().Set("Content-Type", "application/octet-stream")c.Writer.Header().Set("Content-Length", strconv.FormatInt(stat.Size(), 10))c.Writer.Flush()var offset int64 = 0var bufsize int64 = 1024 * 1024 // 1MBbuf := make([]byte, bufsize)for {n, err := file.ReadAt(buf, offset)if err != nil && err != io.EOF {log.Println("read file error", err)break}if n == 0 {break}_, err = c.Writer.Write(buf[:n])if err != nil {log.Println("write file error", err)break}offset += int64(n)}c.Writer.Flush()
}

上述代码中,我们首先打开文件并获取文件状态(文件大小),然后设置一些响应头,包括Content-Disposition(告诉浏览器以附件形式下载文件)、Content-Type(告诉浏览器文件类型)以及Content-Length(告诉浏览器文件大小)。

接下来,我们定义一个缓冲区,大小为1MB(根据实际情况可调整)。然后使用循环读取文件并逐一将数据块发送给客户端。

  1. 实现断点续传

断点续传是指当下载文件过程中,如果网络出现问题或者用户暂停了下载,下一次再进行下载时可以从上一次下载的位置继续开始下载,而不需要从头开始下载。

要实现断点续传,我们需要在响应头中添加一个Content-Range字段,该字段表示当前响应数据的范围。例如,如果当前文件大小为100MB,已经下载了20MB,那么响应头中就可以写成:

Content-Range: bytes 20971520-104857599/104857600

其中,20971520-104857599表示当前响应数据的范围,104857600表示文件总大小。

如何获取已下载的位置?可以从请求头中的Range字段中获取。例如,如果客户端已经下载了20MB,那么请求头中可以写成:

Range: bytes=20971520-

以下是实现断点续传的代码:

import ("io""os""strconv""strings""github.com/gin-gonic/gin"
)
func DownloadFile(c *gin.Context) {filePath := "path/to/file"fileName := "file_name"file, err := os.Open(filePath)if err != nil {c.AbortWithError(404, err)return}defer file.Close()stat, err := file.Stat()if err != nil {c.AbortWithError(404, err)return}c.Writer.Header().Set("Content-Disposition", "attachment; filename="+fileName)c.Writer.Header().Set("Content-Type", "application/octet-stream")c.Writer.Header().Set("Content-Length", strconv.FormatInt(stat.Size(), 10))c.Writer.Flush()var offset int64 = 0var bufsize int64 = 1024 * 1024 // 1MBbuf := make([]byte, bufsize)rangeHeader := c.Request.Header.Get("Range")if rangeHeader != "" {parts := strings.Split(rangeHeader, "=")if len(parts) == 2 && parts[0] == "bytes" {rangeStr := parts[1]ranges := strings.Split(rangeStr, "-")if len(ranges) == 2 {offset, _ = strconv.ParseInt(ranges[0], 10, 64)if offset >= stat.Size() {c.AbortWithError(416, errors.New("Requested Range Not Satisfiable"))return}if ranges[1] != "" {endOffset, _ := strconv.ParseInt(ranges[1], 10, 64)if endOffset >= stat.Size() {endOffset = stat.Size() - 1}c.Writer.Header().Set("Content-Range", "bytes "+ranges[0]+"-"+strconv.FormatInt(endOffset, 10)+"/"+strconv.FormatInt(stat.Size(), 10))c.Writer.Header().Set("Content-Length", strconv.FormatInt(endOffset-offset+1, 10))file.Seek(offset, 0)} else {c.Writer.Header().Set("Content-Range", "bytes "+ranges[0]+"-"+strconv.FormatInt(stat.Size()-1, 10)+"/"+strconv.FormatInt(stat.Size(), 10))c.Writer.Header().Set("Content-Length", strconv.FormatInt(stat.Size()-offset, 10))file.Seek(offset, 0)}c.Writer.WriteHeader(206)}}}for {n, err := file.ReadAt(buf, offset)if err != nil && err != io.EOF {log.Println("read file error", err)break}if n == 0 {break}_, err = c.Writer.Write(buf[:n])if err != nil {log.Println("write file error", err)break}c.Writer.Flush()offset += int64(n)}c.Writer.Flush()
}

上述代码中,在读取文件之前我们先从请求头中获取Range字段,如果存在,就解析出当前下载的起始位置并根据需要设置Content-Range字段和Content-Length字段。如果Range字段的值无效,我们返回416状态码,表示当前所请求的范围不符合要求。

之后,我们按照文件分块读取的方式将数据块发送给客户端。在发送每个数据块之后,我们需要及时调用Flush()方法将数据块发送给客户端,否则会导致下载进度无法实时更新的问题。

参考链接

相关文章:

gin框架实现大文件下载

在gin框架中实现大文件下载主要分为两个步骤: 将文件分块读取 由于大文件一次性读取会占用大量内存,容易导致内存溢出等问题,需要将文件分块读取,逐一发送给客户端。 在gin框架中,可以使用context.File方法向客户端…...

数据可视化-canvas-svg-Echarts

数据可视化 技术栈 canvas <canvas width"300" height"300"></canvas>当没有设置宽度和高度的时候&#xff0c;canvas 会初始化宽度为 300 像素和高度为 150 像素。切记不能通过样式去设置画布的宽度与高度宽高必须通过属性设置&#xff0c;…...

深信服 SG上网优化管理系统 catjs.php 任意文件读取漏洞[2023-HW]

深信服 SG上网优化管理系统 catjs.php 任意文件读取漏洞 一、漏洞描述二、漏洞影响三、网络测绘四、漏洞复现小龙POC检测: 五、 修复建议 免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间…...

java反序列化泛型中json对象

使用 jackson的objectMapper 来实现 import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMa…...

Docker Compose一键管理容器

可以一键批量管理docker的容器。将所有需要创建的容器定义在compose配置文件中&#xff0c;通过一个命令一键可以创建并运行这些容器&#xff0c;而不需要一个一个启动。可以批量启动停止服务。 安装 #安装Docker-Compose并安装到/usr/local/bin/docker-compose curl -L &quo…...

API接口文档利器:Swagger 和 接口调试利器:Postman

2.接口相关工具 2.1API接口文档利器&#xff1a;Swagger 2.1.1Swagger介绍 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTful 风格的 Web 服务 (https://swagger.io/)。 它的主要作用是&#xff1a; 使得前后端分离开发更加方便&#xff0…...

Redis手动实现分布式锁-Demo

1、pom文件依赖 <!--引入Redis操作依赖--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </dependency> 2、具体实现 package com.xch;import org.spring…...

BBS项目day04 文章详情页、点赞点菜、评论功能(根评论和子评论)、评论分页之刷新评论页面

一、路由 from django.contrib import admin from django.urls import path, re_path from app01 import views from django.views.static import serve from django.conf import settingsurlpatterns [path(admin/, admin.site.urls),# 注册path(register/, views.register)…...

【带着学Pytorch】1、pytorch的安装与入门

一、介绍与安装 1.1. pytorch优点: 上手简单:掌握语法和深度学习的概念,尤其是Numpy的使用与python的list切片有共同性。代码灵活:基本调用封装好的模块,动态图使编写更加灵活资源多: 硬件,软件,文档资料都很多。容易调试:动态运行在调试中可以观察数据的变化是否符…...

smartbi token回调获取登录凭证漏洞

2023年7月28日Smartbi官方修复了一处权限绕过漏洞。未经授权的攻击者可利用该漏洞&#xff0c;获取管理员token&#xff0c;完全接管管理员权限。 于是研究了下相关补丁并进行分析。 0x01分析结果 依据补丁分析&#xff0c;得到如下漏洞复现步骤 第一步&#xff0c;设置Engi…...

SQL注入之堆叠查询

文章目录 堆叠查询是什么&#xff1f;堆叠查询修改所有用户密码堆叠查询删除数据库恢复数据库 堆叠查询是什么&#xff1f; 在SQL中&#xff0c;分号;是用来表示一条sql语句的结束。试想一下我们在; 结束一个sql语句后继续构造下一条语句&#xff0c;会不会一起执行&#xff1f…...

java-JVM 类加载机制

JVM 类加载机制 JVM 类加载机制分为五个部分&#xff1a;加载&#xff0c;验证&#xff0c;准备&#xff0c;解析&#xff0c;初始化&#xff0c;下面我们就分别来看一下这五个过程。 1.1. 加载 加载是类加载过程中的一个阶段&#xff0c;这个阶段会在内存中生成一个代表这…...

前端面试:【网络协议与性能优化】提升Web应用性能的策略

嗨&#xff0c;亲爱的Web开发者&#xff01;构建高性能的Web应用是每个开发者的梦想。本文将介绍一些性能优化策略&#xff0c;包括资源加载、懒加载和CDN等&#xff0c;以帮助你提升Web应用的性能。 1. 性能优化策略&#xff1a; 压缩资源&#xff1a; 使用Gzip或Brotli等压缩…...

前端面试:【React】构建现代Web的利器

嘿&#xff0c;亲爱的React探险家&#xff01;在前端开发的旅程中&#xff0c;有一个神奇的库&#xff0c;那就是React。React是一个用于构建现代Web应用的强大工具&#xff0c;它提供了组件化开发、状态管理、生命周期管理和虚拟DOM等特性&#xff0c;让你的应用开发变得更加高…...

使用mysql:5.6和 owncloud 镜像,构建一个个人网盘。

1、使用mysql:5.6和 owncloud 镜像&#xff0c;构建一个个人网盘。 拉取mysql:5.6和owncloud的镜像和生成实例 [rootlocalhost ~]# docker pull mysql:5.6 [rootlocalhost ~]# docker pull ownclound [rootlocalhost ~]# docker run -d --name mydb1 --env MYSQL_ROOT_PASSWO…...

k8s发布应用

前言 首先以SpringBoot应用为例介绍一下k8s的发布步骤。 1.从代码仓库下载代码&#xff0c;比如GitLab&#xff1b; 2.接着是进行打包&#xff0c;比如使用Maven&#xff1b; 3.编写Dockerfile文件&#xff0c;把步骤2产生的包制作成镜像&#xff1b; 4.上传步骤3的镜像到…...

微信小程序教学系列(4)

微信小程序教学系列 第四章&#xff1a;小程序优化与调试 1. 性能优化技巧 在开发微信小程序时&#xff0c;我们可以采取一些性能优化技巧&#xff0c;以提升小程序的性能表现和用户体验。以下是一些常用的性能优化技巧&#xff1a; 减少网络请求&#xff1a;尽量合并网络请…...

Netty核心源码解析(三)--NioEventLoop

NioEventLoop介绍 NioEventLoop继承SingleThreadEventLoop,核心是一个单例线程池,可以理解为单线程,这也是Netty解决线程并发问题的最根本思路--同一个channel连接上的IO事件只由一个线程来处理,NioEventLoop中的单例线程池轮询事件队列,有新的IO事件或者用户提交的task时便执…...

Vue2学习笔记のVue核心

目录 Vue核心初识VueVue模板语法数据绑定el与data的两种写法MVVM模型数据代理Object.defineProperty方法何为数据代理Vue中的数据代理 事件处理事件的基本使用事件修饰符键盘事件 计算属性姓名案例_插值语法实现姓名案例_methods实现姓名案例_计算属性实现姓名案例_计算属性简写…...

把matlab的m文件打包成单独的可执行文件

安装Matlab Compiler Adds-on在app里找到Application Compiler 选择要打包的文件matlab单独的运行程序的话需要把依赖的库做成runtime. 这里有两个选项. 上面那个是需要对方在联网的情况下安装, 安装包较小.下面那个是直接把runtime打包成安装程序, 大概由你的程序依赖的库的多…...

实战指南:如何用Hydra在Kali Linux上快速破解Telnet弱密码(附字典优化技巧)

Kali Linux渗透测试实战&#xff1a;Hydra高效破解Telnet服务的进阶技巧 在渗透测试和网络安全评估中&#xff0c;弱密码检测是基础但至关重要的环节。Telnet作为传统的远程管理协议&#xff0c;由于采用明文传输&#xff0c;成为安全测试的重点对象。本文将深入探讨如何利用Ka…...

从Siwave导入模型到Q3D仿真,如何避免‘幽灵’solder导致的网络报错?

从Siwave到Q3D的模型迁移&#xff1a;彻底解决"幽灵焊料"引发的网络冲突 当你在Ansys电子设计自动化工具链中切换工作环境时&#xff0c;是否遇到过这样的困扰&#xff1a;从Siwave精心准备的模型导入Q3D后&#xff0c;突然冒出各种莫名其妙的网络重叠报错&#xff…...

工业数智化转型路径:JBoltAI 工具与定制化服务实践

当前&#xff0c;我国工业数智化已进入高质量发展、规模化推广的新阶段&#xff0c;成为推动制造业转型升级、构建先进工业体系的核心动力。结合行业发展现状与企业实际需求&#xff0c;JBoltAI推出针对性数智化工具及定制服务&#xff0c;为工业企业转型提供实用支撑。一、工业…...

深度解析 APT:Linux 运维人员的“瑞士军刀”,你真的用对了吗?

在 Linux 的世界里&#xff0c;尤其是对于 Debian 系&#xff08;如 Ubuntu、Linux Mint&#xff09;的用户来说&#xff0c;APT 是一个无法绕开的名字。很多初学者在安装软件时&#xff0c;只知道机械地复制粘贴 sudo apt install 命令&#xff0c;却对背后这套强大的机制知之…...

云容笔谈·东方红颜影像生成系统与ComfyUI工作流集成:可视化节点式创作

云容笔谈东方红颜影像生成系统与ComfyUI工作流集成&#xff1a;可视化节点式创作 如果你是一位数字艺术家或者技术美术&#xff0c;可能常常面临这样的困境&#xff1a;你有一个绝佳的创意&#xff0c;比如想生成一幅融合了东方古典美学与现代光影的“红颜”肖像&#xff0c;但…...

DeepFaceLab 512分辨率遮罩模型实战:如何精准处理头发和手部细节(附下载)

DeepFaceLab 512分辨率遮罩模型实战&#xff1a;如何精准处理头发和手部细节 在数字内容创作领域&#xff0c;视频换脸技术已经从简单的娱乐工具逐渐演变为影视特效、虚拟偶像制作等专业场景的核心技术。对于DeepFaceLab的中高级用户来说&#xff0c;如何突破基础换脸的局限&am…...

EMI滤波器选型指南:从共模与差模噪声到实际应用场景

1. EMI滤波器的核心作用与选型挑战 刚入行那会儿&#xff0c;我负责的第一个电源项目就栽在了EMI测试上。设备一上电&#xff0c;测试仪器的曲线就像心电图发作似的疯狂跳动。当时 mentor 只说了一句&#xff1a;"去查查共模和差模的区别"。这句话成了我后来十年硬件…...

清音刻墨镜像免配置亮点:内置10+中文领域词典(医疗/法律/IT)开箱即用

清音刻墨镜像免配置亮点&#xff1a;内置10中文领域词典&#xff08;医疗/法律/IT&#xff09;开箱即用 1. 为什么字幕对齐需要专业词典&#xff1f; 做视频字幕的朋友都知道&#xff0c;最头疼的不是生成文字&#xff0c;而是让文字和声音完美对齐。普通字幕工具遇到专业术语…...

League Akari:5大核心解决方案提升英雄联盟游戏体验

League Akari&#xff1a;5大核心解决方案提升英雄联盟游戏体验 【免费下载链接】League-Toolkit 兴趣使然的、简单易用的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/League-Toolkit League Akari是一…...

开局掌控者:EdB Prepare Carefully - RimWorld自定义体验革命

开局掌控者&#xff1a;EdB Prepare Carefully - RimWorld自定义体验革命 【免费下载链接】EdBPrepareCarefully EdB Prepare Carefully, a RimWorld mod 项目地址: https://gitcode.com/gh_mirrors/ed/EdBPrepareCarefully 副标题&#xff1a;如何告别随机开局&#xf…...