node中的文件上传与下载
目前项目中常见的文件上传和下载的方式采用的是formData和文件流下载,本文也介绍通过node进行文件的上传和下载处理.
文件流的下载
文件上传
1.文件流上传
//获取上传文件
const file = ctx.request.files.file;
// 读取文件流
const fileReader = fs.createReadStream(file.path);
const filePath ='./public/upload';
// 组装成绝对路径
const fileResource = filePath + `/${file.name}`;
/*
使用 createWriteStream 写入数据,然后使用管道流pipe拼接
*/
const writeStream = fs.createWriteStream(fileResource);
// 判断 /static/upload 文件夹是否存在,如果不在的话就创建一个
if (!fs.existsSync(filePath)) {
fs.mkdir(filePath, (err) => {
if (err) {
throw new Error(err);
} else {
fileReader.pipe(writeStream);
ctx.body = {
url: `http://${getLocalIP()}:3001/public/upload` + `/${file.name}`,
code: 0,
message: '上传成功'
};
}
});
} else {
fileReader.pipe(writeStream);
ctx.body = {
url: `http://${getLocalIP()}:3001/public/upload` + `/${file.name}`,
code: 0,
message: '上传成功'
};
}
2.koa-multer上传
注意这种上传方式 不能使用koa-body插件 可以使用koa-bodyparser, 因为koa-body和koa-multer有冲突
//配置
const multer = require('koa-multer');
const path = require('path');
const storage = multer.diskStorage({
//设置上传的文件夹
destination:'public/uploads/'+new Date().getFullYear() + (new Date().getMonth()+1) + new Date().getDate(),
filename(ctx,file,cb){
//设置文件名称
const filenameArr = file.originalname.split('.');
cb(null,Date.now() + '.' + filenameArr[filenameArr.length-1]);
}
});
const upload = multer({storage});
router.post('/upoload',upload.single('file'),async(ctx,next)=>{
//上传成功
})
文件下载
1.文件流下载
1).使用语与所有文件下载
//文件下载地址
const filePath = path.join(__dirname, 'package.json');
let fileData= await new Promise((resolve,reject)=>{
//异步读取文件
fs.readFile(filePath,{encoding:"utf-8"},(error,data)=>{
if(error){
reject(error)
} else{
resolve(data)
}
})
})
//设置文件的相应头
ctx.set('Content-type', 'application/octet-stream');
ctx.set('Content-Disposition', `'attachment;filename=package.json`);
//改成二进制文件传送,前端通过blob进行接收下载
let buf=Buffer.from(JSON.stringify(fileData))
ctx.body =buf
2).不适用json格式的文件下载
```javascript
const filePath = path.join(__dirname+'/public/upload/', 'Code.exe');
let file = fs.createReadStream(filePath);
try {
await new Promise((resolve, reject) => {
file.on('open', function () {
// 没有特定类型的二进制文件,使用 application/octet-stream
ctx.set('content-type', 'application/octet-stream');
ctx.set('Content-Disposition', `'attachment;filename=Code.exe`);
console.log(file)
ctx.body = file;
resolve();
});
file.on('error', function (err) {
reject(err);
})
});
} catch (e) {
console.error(e);
next();
}
//还有这种方式
ctx.set('content-type', 'application/octet-stream');
ctx.set('Content-Disposition', `'attachment;filename=Code.exe`);
ctx.body = await readFile()
function readFile() {
return new Promise(resolve => {
const filePath = path.join(__dirname + '/public/upload/', 'Code.exe');
let readStream = fs.createReadStream(filePath);
const buffers = [];
readStream.on('data', function (buffer) {
buffers.push(buffer);
});
readStream.on('end', function () {
const data = Buffer.from(buffers);
resolve(data)
});
readStream.on('error', function (error) {
console.error('readStream error:', error.message);
})
})
}
2.koa-send下载(直接返回下载内容)
const path = public/upload/package.json
;
// fileStream.on(‘data’, function (data) {
ctx.set(‘Content-type’, ‘application/octet-stream’);
ctx.set(“Content-disposition”, “attachment; filename=package.json” )
await send(ctx, path)
## 前端常见的文件上传下载
### 文件上传
#### 原生input formData
```javascript
<input type="file" id="file" @change="handleADD">
handleADD(e){
let file=e.target.file
let formData=new FormData()
formData.append('file',file)
//发送地址
axios.get('api地址',formData)
from 表单提交
<form action="上传地址" methods="post" enctype="mulipart/form-data">
<input type="file" name="file"/>
</form>
el-upload
<el-upload
class="upload-demo"
action="/api/file/upload/"
multiple
:limit="3"
:on-success="handleSucces"
:file-list="fileList">
<el-button size="small" type="primary">点击上传</el-button>
<div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
</el-upload>
//这种方式 我们也可以进行参数的添加(在data属性中)添加请求头(headers属性中)
文件下载
a标签直接下载
a标签直接下载 这种一般是服务端直接返回文件内容的方式,对应koa-send的方式或者文件流第二种方式
直接下载
地址栏输入文件URL
window.location.href = URL
window.open(URL)
bolo下载 使用于文件流下载·
let type=res.headers['content-disposition'].split(';')[1].split('=')[1]
let blob=new Blob([res.data])
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = type;
// 兼容旧版本火狐浏览器,将 a 标签插入 DOM 中
document.body.appendChild(a);
a.click();
a.remove();
fs中 readFile(path,fb)//异步读取文件
///路径问题 node中的相对路径则相对的是运行node文件的目录。
//__dirname 则表示的是当前文件的文件夹目录 fileName则是包含当前文件的路径
path.join(a,b)则是将多个路径片段通过\链接起来,形成新的完整路径 path.resolve(/a,/b) 把一个路径解析成一个绝对路径 /则代表根路径