学习node.js十三,文件的上传于下载

文件上传

文件上传的方案:

  1. 大文件上传:将大文件切分成较小的片段(通常称为分片或块),然后逐个上传这些分片。这种方法可以提高上传的稳定性,因为如果某个分片上传失败,只需要重新上传该分片而不需要重新上传整个文件。同时,分片上传还可以利用多个网络连接并行上传多个分片,提高上传速度
  2. 断点续传:在上传过程中,如果网络中断或上传被中止,断点续传技术可以记录已成功上传的分片信息,以便在恢复上传时继续上传未完成的部分,而不需要重新上传整个文件。这种技术可以大大减少上传失败的影响,并节省时间和带宽。
前端实现
<head><meta charset="UTF-8"><title>Title</title><style>input {background-color: #f5f5f5;border: 1px solid #ccc;border-radius: 5px;cursor: pointer;outline: none;font-size: 14px;color: #333;text-align: center;line-height: 30px;font-size: 40px;}</style>
</head>
<body><!--  上传文件  --><input type="file" id="file" name="file" value="上传文件" />
</body>

第一步:获取元素,监听change事件。获取到文件的信息之后,利用file原型上面的 blob对象的slice方法来进行分割

// 获取文件,监听有无上传const file = document.getElementById('file');file.addEventListener('change', function (e) {// 获取文件信息const file = e.target.files[0];const chunks = sliceFile(file);uploadFile(chunks)})// 分片function sliceFile(file, chunkSize = 1024 * 1024 * 3) {let chunks = []for (let i = 0; i < file.size; i+= chunkSize) {chunks.push(file.slice(i, i + chunkSize))}return chunks}

第二步:将这些分片的文件片,编入编号和文件名后以formData的格式上传,并且将结果放入promise.all这个方法中,如果全部成功的化,那么就调用合并函数,将这个视频进行合并

// 上传function uploadFile(chunks) {let list = []for (let i = 0; i < chunks.length; i++) {let formData = new FormData();formData.append('index', i)formData.append('name', "wenjian")formData.append('file', chunks[i])list.push(fetch("http://localhost:8080/upload", {method: 'POST',body: formData}))}// 监听事件是否成功Promise.all(list).then(res => {// 发送合并请求fetch("http://localhost:8080/merge", {method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({name: "ceshi.gif",})}).then(res => {console.log(res)}).catch(e => {console.log(e)})}).catch(e=> {console.log(e)})}
nodejs端实现

安装依赖

  1. express 帮我们启动服务,并且提供接口
  2. multer 读取文件,存储
  3. cors 解决跨域

初始化 multer.diskStorage

  • destination 存储的目录
  • filename 存储的文件名(我是通过index-文件名存储的你也可以改)
// 1. 初始化multer
const storage = multer.diskStorage({destination:function (req,file,cb) {cb(null,'./upload')},filename:function (req,file,cb) {cb(null,`${req.body.index}-${req.body.name}`)}
})

放到接口上面,就可以将分完片的文件上传

// 2. 配置multer
const upload = multer({storage:storage})
// 3. 创建上传接口
app.post('/upload',upload.single('file'),(req,res) => {res.send('上传成功')
})

合并文件:先读取分片文件的文件名,然后把这些文件重新的进行排序,合成一个新的文件

完整代码:

import express from 'express'
import multer from 'multer'
import cors from 'cors'
import fs from 'node:fs'
import path from 'node:path'// 1. 初始化multer
const storage = multer.diskStorage({destination:function (req,file,cb) {cb(null,'./upload')},filename:function (req,file,cb) {cb(null,`${req.body.index}-${req.body.name}`)}
})
const app = express()
app.use(cors())
app.use(express.json())
// 2. 配置multer
const upload = multer({storage:storage})
// 3. 创建上传接口
app.post('/upload',upload.single('file'),(req,res) => {res.send('上传成功')
})
// 4. 合并文件
app.post("/merge",(req,res) => {if(!req.body.name) return res.send('文件名不能为空')let uploadDir = "./upload"// 读取分片文件let files = fs.readdirSync(path.join(process.cwd(), uploadDir))// 重新排序files = files.sort((a,b) => a.split('-')[0] - b.split('-')[0])// 合并文件let writeDir = path.join(process.cwd(),"./video",`${req.body.name}`)files.forEach(item => {fs.appendFileSync(writeDir,fs.readFileSync(path.join(process.cwd(),uploadDir,item)))fs.unlinkSync(path.join(process.cwd(),uploadDir,item))})res.send('合并成功')
})
app.listen(8080,() => console.log('Server is running on port 8080'))

文件流下载

文件流下载是一种通过将文件内容以流的形式发送给客户端,实现文件下载的方法。它适用于处理大型文件或需要实时生成文件内容的情况。

nodejs端实现

响应头

  1. Content-Type 指定下载文件的 MIME 类型
    • application/octet-stream(二进制流数据)
    • application/pdf:Adobe PDF 文件。
    • application/json:JSON 数据文件
    • image/jpeg:JPEG 图像文件
  2. Content-Disposition 指定服务器返回的内容在浏览器中的处理方式。它可以用于控制文件下载、内联显示或其他处理方式
    • attachment:指示浏览器将响应内容作为附件下载。通常与 filename 参数一起使用,用于指定下载文件的名称
    • inline:指示浏览器直接在浏览器窗口中打开响应内容,如果内容是可识别的文件类型(例如图片或 PDF),则在浏览器中内联显

代码实现:

import express from 'express'
import fs from 'fs'
import path from 'path'
import cors from 'cors'const app = express()
app.use(cors())
app.use(express.json())
app.use(express.static(path.join(process.cwd(),"static")))app.post("/upload", (req, res) => {let fileName = req.body.fileNameif(!fileName) return res.send({message: "File name is required"})let filePath = path.join(process.cwd(),"static", fileName)let readStream = fs.readFileSync(filePath)// 设置响应头res.setHeader('Content-Type', 'application/octet-stream')res.setHeader('Content-Disposition', 'attachment;filename=' + fileName)res.send(readStream)
})app.listen(3000,() => console.log('Server is running on port 3000'))

前端逻辑

前端核心逻辑就是接受的返回值是流的方式arrayBuffer,转成blob,生成下载链接,模拟a标签点击下载

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><style>input {background-color: #f5f5f5;border: 1px solid #ccc;border-radius: 5px;cursor: pointer;outline: none;font-size: 14px;color: #333;text-align: center;line-height: 30px;font-size: 40px;}</style>
</head>
<body><!--  上传文件  --><input type="button"  value="下载文件" />
</body>
<script>let btn = document.querySelector('input');btn.onclick = function () {fetch("http://localhost:3000/upload",{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({fileName:'1.png',})}).then(res => res.arrayBuffer()).then(res => {// 1. 转为bloblet blob = new Blob([res],{type:'image/png'})// 2. 创建a标签let a = document.createElement('a')// 4. 设置a标签的href属性为blob地址a.href = URL.createObjectURL(blob)// 3. 设置下载文件名a.download = '1.png'// 5. 模拟点击a标签a.click()// 6. 移除a标签a.remove()})}
</script>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/52587.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

无人机电调接线

接线方式&#xff1a; 电调的作用是将飞控板的PWM控制信号转变为电流信号 因为电机的电流是很大的&#xff0c;通常每个点击正常工作时都平均有3A左右的电流&#xff0c;如果没有电调的存在&#xff0c;飞控无法承受这么大的电流。 电调的选择&#xff1a;电调上标的电流值是…

六、图结构

文章目录 一、引入二、基本概念三、图的表示四、图的遍历4.1 图的深度优先遍历&#xff08;DFS&#xff09;4.2 图的广度优先遍历&#xff08;BFS&#xff09;4.3 图的深度优先 VS 广度优先 一、引入 二、基本概念 三、图的表示 package com.gyh.grapg;import java.util.ArrayL…

udt聊天室

创建一个简单的udp聊天室 服务器代码思路&#xff1a; 初始化&#xff1a; 创建UDP套接字。配置服务器的IP和端口号&#xff0c;并绑定套接字到这个地址。 数据接收和处理&#xff1a; 使用循环接收客户端发来的消息。recvfrom()解析消息类型&#xff08;如登录、发送、下线&a…

OpenCV结构分析与形状描述符(22)计算图像中某个轮廓或区域的矩函数moments()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 计算一个多边形或光栅化形状直到三阶的所有矩。 该函数计算一个向量形状或光栅化形状直到三阶的矩。结果返回在 cv::Moments 结构中。 函数原型…

基本输入与输出

引言 在前面的课程中&#xff0c;我们已经学习了 Python 中的基本数据类型、数据类型的运算和转换。本课时将聚焦于 Python 中的基本输入与输出功能&#xff0c;具体包括使用 input() 函数获取用户输入、使用 print() 函数输出信息以及格式化输出。通过这些功能&#xff0c;你可…

ATF UFS初始化笔记

1. JESD220 中关于UFS初始化的描述 原文 13.1.3 Initialization and boot code download process The initialization and boot code download process is made up of the following phases: partial initialization, boot transfer and initialization completion. 13.1.3.…

多线程——死锁

死锁 在Java中使用多线程&#xff0c;就会有可能导致死锁问题。死锁会让程序一直卡住&#xff0c;程序不再往下执行。 我们只能通过中止并重启的方式来让程序重新执行。 这是我们非常不愿意看到的一种现象&#xff0c;我们要尽可能避免死锁的情况发生&#xff01; 死锁的原因…

数据结构之栈和队列的应用

目录 一、栈的应用 1. 括号匹配 2. 计算后缀表达式 方法一&#xff08;栈&#xff09; 方法二&#xff08;数组模拟栈&#xff09; 二、队列应用 1. 二叉树层序遍历 方法一&#xff08;队列&#xff09; 三、总结 一、栈的应用 1. 括号匹配 给定一个只包括 (&#xf…

List<Map<String, Object>>汇总统计排序

开发环境&#xff1a;jdk 1.8 需求一&#xff1a; 1、统计每个小时(升序)不同事件的产品产量 2、统计不同事件&#xff08;OK 、NG&#xff09;的总产量 public static void main(String[] args) {//数据源List<Map<String, Object>> list new ArrayList<Map…

云计算实训48——k8s环境搭建(详细版)

1.创建主机、设置ip、设置hostname 2.设置免密登录 # 生成私钥 [rootk8s-master ~]# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): /root/.ssh/id_rsa already exists. Overwrite (y/n)? y Enter passphr…

77-java 装饰器模式和适配器模式区别

‌Java中的装饰器模式和适配器模式虽然都涉及到对象的组合和包装&#xff0c;但它们的应用场景和目的有所不同。‌ ‌装饰器模式的目的是在不修改原始对象的基础上&#xff0c;动态地添加功能或行为。‌它允许用户通过创建一个包含原始对象的包装类&#xff08;装饰器&#xff…

Computer Vision的学习路线

学习**Computer Vision&#xff08;计算机视觉&#xff09;**的过程中&#xff0c;可以按照以下步骤循序渐进地掌握基础知识、算法和实际应用。这个学习路线将涵盖从基础理论到前沿技术的各个层面。 1. 数学与基础知识 1.1 线性代数 计算机视觉中的图像处理和模型训练都依赖…

Uni-app 开发微信小程序

随着移动互联网的发展&#xff0c;微信小程序已经成为一种流行的应用开发模式。Uni-app 作为一种跨平台的开发框架&#xff0c;使用 Vue.js 语法&#xff0c;能够方便快速地开发出 微信小程序、H5、App 等多端应用。本指南将引导您从环境配置到实战案例开发&#xff0c;帮助您快…

vue3 使用swiper制作带缩略图的轮播图

效果图 实现代码 <template><div class"wrap"><!-- 主轮播图 --><swiper :style"{--swiper-navigation-color: #fff,--swiper-pagination-color: #fff,}" :modules"modules" :navigation"true" :thumbs"{ …

计算机网络 第2章 物理层

文章目录 通信基础基本概念信道的极限容量编码与调制常用的编码方法常用的调制方法 传输介质双绞线同轴电缆光纤以太网对有限传输介质的命名规则无线传输介质物理层接口的特性 物理层设备中继器集线器一些特性 物理层任务&#xff1a;实现相邻节点之间比特&#xff08;0或1&…

GORM高级查询

在日常开发中&#xff0c;我们经常需要执行复杂的数据库查询以满足各种业务需求。GORM作为Go语言中一个流行的ORM库&#xff0c;提供了许多高级查询功能&#xff0c;可以帮助我们高效地处理这些复杂场景。本文将详细介绍GORM的高级查询功能&#xff0c;包括智能选择字段、锁、子…

pptpd配置文件/etc/pptpd.conf详解

正文共&#xff1a;1111 字 2 图&#xff0c;预估阅读时间&#xff1a;1 分钟 如果要在Linux系统配置PPTP&#xff08;Point-to-Point Tunneling Protocol&#xff0c;点到点隧道协议&#xff09;VPN&#xff0c;一般是使用pptpd软件。pptpd命令通常从配置文件/etc/pptpd.conf中…

单片机拍照_将采集的RGB图像封装为BMP格式保存到SD卡

文章目录 一、前言二、BMP文件结构2.1 BMP图片的格式说明 2.2 RGB888与RGB565格式是什么&#xff1f;&#xff08;1&#xff09;RGB565&#xff08;2&#xff09;RGB888&#xff08;3&#xff09;区别&#xff08;4&#xff09;如何构成&#xff08;5&#xff09;示例 三、实现…

【Leetcode56】合并区间(数组 | 排序)

文章目录 一、题目二、思路三、代码 一、题目 二、思路 先将所有子列表按照start_pos进行排序&#xff0c;有利于保持顺序性&#xff0c;每次处理新子列表时&#xff0c;只用和结果列表ans_lst的最后一个子列表对比&#xff0c;如果有重合则合并&#xff0c;然后将合并的新子列…

Java 入门指南:Java 并发编程 —— 同步工具类 Phaser(相位器)

文章目录 同步工具类Phaser主要特点核心方法使用步骤适用场景使用示例 同步工具类 JUC&#xff08;Java.util.concurrent&#xff09;是 Java 提供的用于并发编程的工具类库&#xff0c;其中包含了一些通信工具类&#xff0c;用于在多个线程之间进行协调和通信&#xff0c;特别…