node进阶之用流实现上传文件
内容:
1.文件上传基础
2.node文件处理机制
3.用流实现文件上传
1.文件上传基础
前端代码:
- <form action="localhost:8080/" method="post" enctype="multipart/form-data">
- <input type="file" name="f1">
- <input type="submit" value="上传文件">
- </form>
- 注意:
- 上传文件时表单中的enctype="multipart/form-data"必须要写
- input(file)必须要有name
后端代码:
- const http = require('http');
- const uuid = require('uuid/v4');
- const fs = require('fs')
- let server_post = http.createServer((req, res) => {
- let arr = [];
- req.on('data', data => {
- arr.push(data);
- });
- req.on('end', () => {
- let data = Buffer.concat(arr);
- // console.log(data)
- //data
- //解析二进制文件上传数据
- let post = {};
- let files = {};
- if (req.headers['content-type']) {
- let str = req.headers['content-type'].split('; ')[1];
- if (str) {
- let boundary = '--' + str.split('=')[1];
- //1.用"分隔符切分整个数据"
- let arr = (data.toString()).split(boundary);
- //2.丢弃头尾两个数据
- arr.shift();
- arr.pop();
- //3.丢弃掉每个数据头尾的"\r\n"
- arr = arr.map(buffer => buffer.slice(2, buffer.length - 2));
- //4.每个数据在第一个"\r\n\r\n"处切成两半
- arr.forEach(buffer => {
- let n = buffer.indexOf('\r\n\r\n');
- let disposition = buffer.slice(0, n);
- let content = buffer.slice(n + 4);
- disposition = disposition.toString();
- if (disposition.indexOf('\r\n') === -1) {
- //普通数据
- //Content-Disposition: form-data; name="user"
- content = content.toString();
- let name = disposition.split('; ')[1].split('=')[1];
- name = name.substring(1, name.length - 1);
- post[name] = content;
- } else {
- //文件数据
- /*Content-Disposition: form-data; name="f1"; filename="a.txt"\r\n
- Content-Type: text/plain*/
- let [line1, line2] = disposition.split('\r\n');
- let [, name, filename] = line1.split('; ');
- let type = line2.split(': ')[1];
- name = name.split('=')[1];
- name = name.substring(1, name.length - 1);
- filename = filename.split('=')[1];
- filename = filename.substring(1, filename.length - 1);
- let path = `upload/${uuid().replace(/\-/g, '')}`;
- fs.writeFile(path, content, err => {
- if (err) {
- console.log('文件写入失败', err);
- } else {
- files[name] = {filename, path, type};
- console.log(files);
- }
- });
- }
- });
- //5.完成
- console.log(post);
- }
- }
- res.end();
- });
- });
- server_post.listen(8080);
2.node文件处理机制
node文件上传从根本上来说就两种方法:
(1)最基础原始的方法
使用fs中的readFile和writeFile实现(读取完上传的文件后保存)
这样做有弊端:
- 只能等到所有数据都到达了才开始处理
- readFile先把所有数据全读到内存中,然后回调:
- 1.极其占用内存
- 2.资源利用极其不充分
(2)更好的方法
使用流,收到一部分数据就直接解析一部分,实例见后面的文件上传实例
3.用流实现文件上传
(1)流
三种流:
- 读取流 --> fs.createReadStream、req
- 写入流 --> fs.createWriteStream、res
- 读写流 --> 压缩、加密
(2)流实现读写文件
- const fs = require('fs')
- let rs = fs.createReadStream('1.txt') // 读取流
- let ws = fs.createWriteStream('2.txt') // 写入流
- rs.pipe(ws)
- // 异常处理
- rs.on('error', function (error) {
- console.log('读取失败!')
- })
- // 读取完成 及 写入完成
- rs.on('end', function () {
- console.log('读取完成!')
- })
- ws.on('finish', function () {
- console.log('写入完成!')
- })
注:1.txt应该在同级目录下
(3)用流实现上传文件核心代码
- /**
- * [saveFileWithStream description]
- * @param {String} filePath [文件路径]
- * @param {Buffer} readData [Buffer 数据]
- */
- static saveFile(filePath, fileData) {
- return new Promise((resolve, reject) => {
- // 块方式写入文件
- const wstream = fs.createWriteStream(filePath);
- wstream.on('open', () => {
- const blockSize = 128;
- const nbBlocks = Math.ceil(fileData.length / (blockSize));
- for (let i = 0; i < nbBlocks; i += 1) {
- const currentBlock = fileData.slice(
- blockSize * i,
- Math.min(blockSize * (i + 1), fileData.length),
- );
- wstream.write(currentBlock);
- }
- wstream.end();
- });
- wstream.on('error', (err) => { reject(err); });
- wstream.on('finish', () => { resolve(true); });
- });
- }
- // 实际调用的时候,如下:
- try {
- await saveFileWithStream(filePath, fileData); // 这里的fileData是Buffer类型
- } catch (err) {
- console.log(err.stack);
- }
node进阶之用流实现上传文件的更多相关文章
- [Node.js] 使用File API 异步上传文件
原文地址:http://www.moye.me/2014/11/05/html5-filereader/ 最近在做一个网盘的项目,不出意外的涉及到大文件的上传,那么问题来了:如何实时的显示文件上传的进 ...
- js上传文件获取文件流
上传文件获取文件流 <div> 上传文件 : <input type="file" name = "file" id = "file ...
- 记录一次node中台转发表单上传文件到后台过程
首发掘金 记录一次node中台转发表单上传文件到后台过程 本篇跟掘金为同一个作者leung 公司几个项目都是三层架构模式即前台,中台(中间层),后台.前台微信端公众号使用vue框架,后台管理前端使 ...
- PHP流式上传和表单上传(美图秀秀)
最近需要开发一个头像上传的功能,找了很多都需要授权的,后来找到了美图秀秀,功能非常好用. <?php /** * Note:for octet-stream upload * 这个是流式上传PH ...
- Asp.net上传文件后台通过二进制流发送到其他Url保存
实际情况一般有单独的站点存放静态文件,比如图片.office文档等.A站点的操作需要上传文件到B站点, 下面介绍一种方法通过System.Net.WebClient类的UploadData方法 . u ...
- 上传文件报错System.Net.ProtocolViolationException: 必须先将 ContentLength 字节写入请求流,然后再调用 [Begin]GetResponse。
在上传文件的时候报错. 错误: System.Net.ProtocolViolationException: 必须先将 ContentLength 字节写入请求流,然后再调用 [Begin]GetRe ...
- Nodejs学习笔记(八)--- Node.js + Express 实现上传文件功能(felixge/node-formidable)
目录 前言 formidable简介 创建项目并安装formidable 实现上传功能 运行结果 部分疑惑解析 写在之后 前言 前面讲了一个构建网站的示例,这次在此基础上再说说web的常规功能---- ...
- c#上传文件(二)使用文件流保存文件
1.html代码: <asp:FileUpload runat="server" ID="UpLoadFile"/> <asp:Button ...
- IOS--工作总结--post上传文件(以流的方式上传)
1.添加协议 <NSURLConnectionDelegate> 2.创建 @property (nonatomic,retain) NSURLConnection* aSynConnec ...
随机推荐
- eclipse ubuntu error
eclipse cdt :symbol cout can not be solved Preferences -> C/C++ -> Indexer -> Use active bu ...
- easyui学习笔记10—手风琴格子始终展开和多个格子展开
始终打开有时候可能会很管用,其实就是一个设置问题.这里就不再介绍引用的资源了,这里只看看html是怎么写的. 1.html代码 <body> <h2>Basic Accordi ...
- Mr. Kitayuta's Colorful Graph CodeForces - 506D(均摊复杂度)
Mr. Kitayuta has just bought an undirected graph with n vertices and m edges. The vertices of the gr ...
- HDU2034:人见人爱A-B
Problem Description 参加过上个月月赛的同学一定还记得其中的一个最简单的题目,就是{A}+{B},那个题目求的是两个集合的并集,今天我们这个A-B求的是两个集合的差,就是做集合的减法 ...
- Linux Shell查看物理CPU个数、核数、逻辑CPU个数
Linux Shell常用命令: ====================================== # 总核数 = 物理CPU个数 X 每颗物理CPU的核数 # 总逻辑CPU数 = 物理C ...
- 有向图与无向图的合并操作区别D(递归与并查集)
有向图的合并,典型问题:通知小弟(信息只能单向传播)https://www.nowcoder.com/acm/contest/76/E 无向图的合并,典型问题:修道路问题 由于无向图只要二者有联系即可 ...
- YUI JS压缩Ant脚本
<?xml version="1.0" encoding="UTF-8"?><!-- 对指定目录下的所有js进行压缩,放入指定位置 --> ...
- statik golang 静态资源嵌入二进制文件工具使用(docker 构建)
将静态资源打包进二进制文件有好多方便的地方 方便客户演示 代码简单加密 运行方便 statik 就是一款在golang 中用的比较多,nodejs 有一款pkg (oclif 就推荐使用此工具) ...
- Postman 常用测试结果验证及使用技巧
Postman的test本质上是JavaScript代码,通过我们编写测试代码,每一个tests返回True,或是False.每一个tests实际上就是一个测试用例 官方文档给出了很多验证方式,我们通 ...
- spring答题
ioc 依赖注入:通过注入的方式实例化对象,不再直接new对象了,交给spring容器进行管理和维护 控制反转:实例化对象的控制权交给了spring容器,而不再是某个单独的类,控制权发生了变更 作用: ...