上传方式
- file 直接读取
- stream 流的方式:创建文件写入流,以管道方式写入流
file 读取
- config 配置
// config.defult.js config.multipart = { mode: 'file', tmpdir: // 配置文件缓存目录 cleanSchedule: { cron: '0 30 4 * * *', // 自动清除时间 文件缓存 }, };
|
读取并存储
const fs = require('fs') const path = require('path') const Controller = require('egg').Controller;
class HomeController extends Controller { async index() { const { ctx } = this; // console.log(ctx.request.body) let file = ctx.request.files[0] // file包含了文件名,文件类型,大小,路径等信息,可以自己打印下看看 // 读取文件 let file = fs.readFileSync(file.filepath) //files[0]表示获取第一个文件,若前端上传多个文件则可以遍历这个数组对象 // 将文件存到指定位置 fs.writeFileSync(path.join('./', `uploadfile/test.png`), file) // ctx.cleanupRequestFiles() ctx.body = { code: 200, message: '', data: file.filename} } }
|
stream 流方式
无需对 config 配置
注意使用 stream 流方式需要把之前配置里的 multipart 删掉,这两种方法不能一起用,否则会报错。
单个文件
const fs = require("fs"); const path = require("path"); const querystring = require("querystring"); const sendToWormhole = require("stream-wormhole"); const Controller = require("egg").Controller;
class HomeController extends Controller { async index() { const { ctx } = this;
let stream = await ctx.getFileStream(); let filename = new Date().getTime() + stream.filename;
let target = path.join("./", `uploadfile/${filename}`);
const result = await new Promise((resolve, reject) => { const remoteFileStrem = fs.createWriteStream(target); stream.pipe(remoteFileStrem);
let errFlag; remoteFileStrem.on("error", (err) => { errFlag = true; sendToWormhole(stream); remoteFileStrem.destroy(); console.log(err); reject(err); });
remoteFileStrem.on("finish", () => { if (errFlag) return; resolve({ filename, name: stream.fields.name }); }); });
ctx.body = { code: 200, message: "", data: result }; } }
|
多个文件
const fs = require("fs"); const path = require("path"); const querystring = require("querystring"); const Controller = require("egg").Controller;
class HomeController extends Controller { async index() { const { ctx } = this;
const parts = ctx.multipart(); let part; while ((part = await parts()) != null) { if (part.length) { console.log("field: " + part[0]); console.log("value: " + part[1]); console.log("valueTruncated: " + part[2]); console.log("fieldnameTruncated: " + part[3]); } else { if (!part.filename) { continue; } console.log("field: " + part.fieldname); console.log("filename: " + part.filename); console.log("encoding: " + part.encoding); console.log("mime: " + part.mime); let writePath = path.join( "./", `uploadfile/${new Date().getTime() + part.filename}` ); let writeStrem = fs.createWriteStream(writePath); await part.pipe(writeStrem); } }
ctx.body = { code: 200, message: "", data: result }; } }
|
两种方式比较
file 读取的方式要简单的多,但在性能上,Stream 更优
使用 file 读取的方式我们可以得到 filepath 这个路径,这个路径是用于缓存文件的地方,大家可以打印一下看看。在该路径中可以找到上传的文件。

file 读取方式是先在服务器里写入缓存文件,然后我们再读取缓存文件进行操作。在上面的文件操作中 file 读取方式的 IO 操作有写入缓存文件,读取缓存文件,写入文件,总共 3 次 IO 操作。而 stream 流的方式没有缓存文件这个操作,也就是说 IO 操作只有一次,若是不将写入本服务器而是上传的 OSS 等则没有 IO 操作。那么这两种方式的效应和性能无疑是 Strram 更优
path.join 和 resolve
|
|
1 |
path.join([path1][, path2][, …]) 用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix 系统是”/“,Windows 系统是”"。 |
2 |
path.resolve([from …], to)将to参数解析为绝对路径,给定的路径的序列是从右往左被处理的,后面每个 path 被依次解析,直到构造完成一个绝对路径。 例如,给定的路径片段的序列为:/foo、/bar、baz,则调用 path.resolve(‘/foo’, ‘/bar’, ‘baz’) 会返回 /bar/baz。 |
path.resolve 返回绝对路径
path.join 返回相对路径,并且会正确使用当前系统的路径分隔符;
参考:javascript - egg 文件上传接收总结_个人文章 - SegmentFault 思否