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 ...
随机推荐
- 一定要记住这20种PS技术,让你的照片美的不行! - imsoft.cnblogs
照片名称:调出照片柔和的蓝黄色-简单方法, 1.打开原图素材,按Ctrl + J把背景图层复制一层,点通道面板,选择蓝色通道,图像 > 应用图像,图层为背景,混合为正片叠底,不透明度50%,反相 ...
- HTML5和CSS3阶段,我是如何学习的?
经过一个月的学习,我收获了许多,今天的测验是做一个企业中文网站,令我自己感到吃惊的是,我前前后后用了4个小时就完成了,这在一个月前根本不可能,因为对布局属性的理解还不够深刻,常常会在调试中浪费大量时间 ...
- Python 操作Excel之通过xlutils实现在保留原格式的情况下追加写入数据
在Python操作Excel 的模块有 xlrd.xlwt.xlutils等. xlrd:读取Excel文件数据 xlwt:写入Excel 数据,缺点是Excel格式无法复用,为了方便用户,写入的话, ...
- [题解] CodeM美团点评编程竞赛资格赛题
最近看到牛课网美团一个编程竞赛,想着做做看,结果一写就是两天..真是写不动了啊.话不多说,下面开始我的题解. 题目大致还是比较考察思维和代码能力(因为自己代码能力较弱,才会觉得比较考察代码能力吧= = ...
- 树莓派做下载机+Web服务器(Aria2下载+yaaw做UI+nginx)
今天收到了小派,UK产的绿板子,还配了个透明盒子,装在里面闪亮亮的很好看,而且只有卡片大小,寻思着用它做什么好呢?想来想去,看到人家拿小派作家庭媒体中心,还有人拿它当下载机,于是就萌生了一个家庭媒体中 ...
- HTTP 返回状态消息讲解
当浏览器从 web 服务器请求服务时,可能会发生错误. 从而有可能会返回下面的一系列状态消息: 1xx: 信息 消息: 描述: 100 Continue 服务器仅接收到部分请求,但是一旦服务器并没有拒 ...
- FastAdmin 如何用 composer bower 安装
FastAdmin 如何安装 composer bower 众所周知的原因,compower bower 安装并不怎么稳定. 刚开始安装时还有侥幸,用软件安装里的设置端口代理,composer 倒是可 ...
- php curl伪造来源ip和refer实例代码
php curl伪造来源ip和来路refer实例代码1: //随机IP function Rand_IP(){ $ip2id= round(rand(600000, 2550000) / 10000) ...
- VS2010编译和运行项目错误
打开工程提示如下: The 'Microsoft.Data.Entity.Design.BootstrapPackage.BootstrapPackage, Microsoft.Data.Entity ...
- Linux C程序操作Mysql 调用PHP采集淘宝商品 (转)
还是继续这个项目. 在上一篇Linux下利用Shell使PHP并发采集淘宝产品中,采用shell将对PHP的调用推到后台执行,模拟多线程. 此方法有一致命缺点,只能人工预判每个程序执行时间.如果判断时 ...