一、简单介绍
1、安装
npm i await-stream-ready -S //异步进行读写操作
npm i stream-wormhole -S //在文件上传出现异常时能够把流消耗掉。
2、引入
const awaitWriteStream = require('await-stream-ready').write;
const sendToWormhole = require('stream-wormhole');
3、获取流
const stream = await ctx.getFileStream();
4、生成文件名
const filename = stream.filename; //可以自定义,这里直接使用上传的文件名
5、生成文件路径
const target = path.join('app/public/uploads', filename);//同样可以自己定义放在哪个文件夹,但是要是在public下面的子文件夹
6、生成文件写入文件流
const writeStream = fs.createWriteStream(target);
7、异步写入文件流
try {
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
await sendToWormhole(stream);
throw err;
}
二、项目实战
首先写一个基类
// controller/core/base.js文件夹下
const { Controller } = require('egg');
const fs = require('fs');
const path = require('path');
//异步二进制 写入流
const awaitWriteStream = require('await-stream-ready').write;
//管道读入一个虫洞
const sendToWormhole = require('stream-wormhole');
//时间格式化
const dayjs = require('dayjs');
class BaseController extends Controller {
async uploadFile(category = '') {// category传过来的分开文件格式的目录
//获取文件流
const stream = await this.ctx.getFileStream();
// 基础的目录
const uploadBasePath = 'app/public/uploads';
//生成文件名
const filename = `${Date.now()}${Number.parseInt(Math.random() * 1000)}${path.extname(stream.filename).toLocaleLowerCase()}`;
//生成文件夹
const dirname = dayjs(Date.now()).format('YYYY/MM/DD');
//创建目录
function mkdirsSync(dirname) {
if(fs.existsSync(dirname)) { //fs.existsSync检测目录是否存在,存在返回true,反之亦然
return true;
} else {
if(mkdirsSync(path.dirname(dirname))) {//返回 path 的目录名,尾部的文件名会被忽略path.dirname('/目录1/目录2/目录3');返回'/目录1/目录2'
fs.mkdirSync(dirname);//fs.mkdirSync同步地创建目录
return true;
}
}
}
mkdirsSync(path.join(uploadBasePath, category, dirname));//path.join,以特定的分隔符将路径连接起来
// 生成写入路径
const target = path.join(uploadBasePath, category, dirname, filename);
// 写入流
const writeStream = fs.createWriteStream(target);
try {
//异步把文件流 写入
await awaitWriteStream(stream.pipe(writeStream));
} catch (err) {
//如果出现错误,关闭管道
await sendToWormhole(stream);
return Promise.reject('上传错误')
}
return Promise.resolve({
url: path.join('/public/uploads', category, dirname, filename),
fields: stream.fields,
});
}
}
module.exports = BaseController;
其次在上传文件的控制器中使用
// controller/file/index.js文件夹下,文件夹可自定义
```javascript
'use strict';
const Controller = require('./../core/base');
class FileController extends Controller {
//上传头像
async headPortrait() {
const { ctx } = this;
// 上传头像的,会在uploads文件夹下有个headPortrait的文件夹下面才是时间文件夹
try {
const { url, fields } = await this.uploadFile('headPortrait');
ctx.body = {
code: 200,
message: '上传成功',
data: {
url,
fields
}
}
} catch(err) {
ctx.body = {
code: 500,
message: err,
}
}
}
}
module.exports = FileController;