文件上传方式以及回显

后端文件的保存方式:文件保存到服务器上,数据库中存文件的地址

方式一:通过formData添加文件,后端通过流来读取并写入保存到服务器上
前端:

getFiles () {
	var that = this
	var FormDataImg = new FormData()
	FormDataImg.append('file', that.$refs.file.files[0]) 上传Blob
	
	axios({
	    url: 'http://192.168.0.177:3030/test/uploadFile',
	    method: 'post',
	    data: FormDataImg,
	    header: {'Content-Type': 'multipart/form-data'}
	}).then(res => {
	    that.$toast('上传成功')
	    that.imgurl = res.data.data1
	}).catch(err => {
	    that.$toast('上传错误')
	})
}

后端:

const fs         = require('fs')
const path       = require('path')
const koaBody    = require('koa-body')                      //上传文件的中间件(用来获取上传的文件)
const koaStatic  = require('koa-static')                    //静态资源的使用(通过域名访问)
app.use(koaBody({
        multipart: true,
        formidable: {
            maxFileSize: 20 * 1024 * 1024    // 设置上传文件大小最大限制,默认2M
        }
    }))
app.use(koaStatic('./public'))//设置访问静态资源(例如:http://localhost:3030/fll.jpg)

exports.uploadFile = async function (ctx) {
    //直接保存图片(大小不变)
    //必须要安装koa-body才能通过ctx.request.files来获取图片信息
    let file = await ctx.request.files.file
    //创建可读流
    let read = await fs.createReadStream(file.path)
    //设置文件保存路径
    let imgPath = await path.join(__dirname, `../../public/${file.name}`)
    // 创建可写流
    let upStream = await fs.createWriteStream(imgPath)
    // 可读流通过管道写入可写流
    await read.pipe(upStream)
    ctx.response.body = {
        message: '上传成功',
        data: ctx.request.files.file,
        data1: `http://192.168.0.177:3030/${ctx.request.files.file.name}`
    }
}

方式二:前端使用form表单提交,后端使用multer(类似的还有multiparty)进行文件保存
前端

<!DOCTYPE html>
<html lang="en">
 
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
    <form action="/upload" method="post" enctype="multipart/form-data">
        <h2>单图上传</h2>
        <input type="file" name="logo">
        <input type="submit" value="提交">
    </form>
<body>
    
</body>
</html>

后端

// // 更改大文件的存储路径
// var createFolder = function(folder){
//     try{
//         fs.accessSync(folder);
//     }catch( e ){
//         fs.mkdirSync(folder);
//     }
// };
 
// var uploadFolder = './upload/';// 设定存储文件夹为当前目录下的 /upload 文件夹
 
// createFolder(uploadFolder);
 
// 磁盘存贮
var storage = multer.diskStorage({
    destination: function (req, file, cb) {
        cb(null, uploadFolder );// 他会放在当前目录下的 /upload 文件夹下(没有该文件夹,就新建一个)
    },
    filename: function (req, file, cb) {// 在这里设定文件名
        cb(null, file.originalname );
    }
})
   
var upload = multer({ storage: storage })

app.post('/upload', upload.single('logo'), function(req, res){//发送 json 数据到这个路由
    console.dir(req.file);
    res.send(req.p);
})

multer保存文件,通过流的方式返回前端下载
前端:

    <el-upload
      class="upload-demo"
      action="http://localhost:9010/table/uploadFile"
      :on-preview="handlePreview"
      :on-remove="handleRemove"
      :before-remove="beforeRemove"
      multiple
      :limit="3"
      :on-exceed="handleExceed"
      :file-list="fileList" ref="elupload">
      <el-button size="small" type="primary">点击上传</el-button>
      <div slot="tip" class="el-upload__tip">只能上传jpg/png文件,且不超过500kb</div>
    </el-upload>

后端:

var multer = require('multer');//引入multer
var upload = multer({dest: 'uploads/'});//设置上传文件存储地址
router.post('/uploadFile', upload.single('file'), (req, res, next) => {
 
    let ret = {};
    ret['code'] = 20000;
    var file = req.file;
    if (file) {
        var fileNameArr = file.originalname.split('.');
        var suffix = fileNameArr[fileNameArr.length - 1];
        //文件重命名
        fs.renameSync('./uploads/' + file.filename, `./uploads/${file.filename}.${suffix}`);
        file['newfilename'] = `${file.filename}.${suffix}`;
    }
    ret['file'] = file;
    res.send(ret);
})

下载
router.use('/downloadFile', (req, res, next) => {
    var filename = req.query.filename;
    var oldname = req.query.oldname;
    var file = './uploads/' + filename;
    res.writeHead(200, {
        'Content-Type': 'application/octet-stream',//告诉浏览器这是一个二进制文件
        'Content-Disposition': 'attachment; filename=' + encodeURI(oldname),//告诉浏览器这是一个需要下载的文件
    });//设置响应头
    var readStream = fs.createReadStream(file);//得到文件输入流
    debugger
    readStream.on('data', (chunk) => {
        res.write(chunk, 'binary');//文档内容以二进制的格式写到response的输出流
    });
    readStream.on('end', () => {
        res.end();
    })
})

前端
const downloadUrl = url => {
  let iframe = document.createElement('iframe');
  iframe.style.display = 'none'
  iframe.src = url
  iframe.onload = function () {
    document.body.removeChild(iframe)
  }
  document.body.appendChild(iframe)
};
module.exports=downloadUrl;

后端通过buffer存储上传的文件
前端:

uploadFile(){  //上传文件

     var file = document.querySelector("#file").files[0]; //获取上传文件
     var formdata = new FormData();
     formdata.append("file",file);
     var xhr = new XMLHttpRequest();
     xhr.open("post","http://xxx/fileInfo/");
     xhr.onreadystatechange = function () {
         if (xhr.readyState === 4 && xhr.status==200){
                  console.log('上传结束')
         }
     }
     xhr.upload.onprogress = function (event) {
         if(event.lengthComputable){
             console.log('------>'+event.loaded/event.total *100+'%')  //显示上传进度
         }
     }
     xhr.send(formdata);
 },

loadFile(){ //下载文件
       var xhr = new XMLHttpRequest();
       xhr.open("post","http://xxx/fileInfo/fileInfo/load");
       xhr.send({});
       xhr.onreadystatechange = function () { //获取下载结果
           console.log('onreadystatechange --------')
           if (xhr.readyState === 4 && xhr.status==200){
               let response = xhr.response
               response = JSON.parse(response)
               console.log(response.file)
               let file = response.file //文件数据
               let filename = response.name //文件名称
               let filetype = response.type //文件类型
               console.log(`文件名:${filename} --- 文件类型:${filetype}  --- 下载中...`)
               let loadBuffer = Buffer.from(file)
               let blob = new Blob([loadBuffer], {type: filetype}) //表示一个不可变、原始数据的类文件对象,想仔细了解可以自行搜索
               //生成临时元素自动下载
               let a = document.createElement('a')
               a.download = filename
               a.href = URL.createObjectURL(blob)
               document.body.appendChild(a)
               a.click()
               document.body.removeChild(a)
           }
       }
   },

}

</script>

后端

//上传接口

router.post("/", async (ctx) => {
  try {
    let files = ctx.request.body.files; //获取文件流
    let file = files.file; //获取上传文件
    let filetype = file.type; //获取上传文件类型
    let filename = file.name; //获取上传文件名称
    let fileReader = fs.createReadStream(file.path); //fs读取文件流

    //读取数据内置的事件监听
    let str = "";
    fileReader.on("data", (chunk) => {
      //fs获取读取的文件流
      //chunk是Buffer
      str += chunk.toString("binary"); //将文件流转换为二进制数据
    });
    fileReader.on("end", () => {
      //文件流读取完成
      //将读取完成的文件数据保存数据库或者其他
      let body = {
        file: str,
        type: filetype,
        name: filename,
      };
    });

    ctx.body = { msg: "上传成功" };
  } catch (err) {
    console.log(err);
    ctx.body = err;
  }
});

//下载接口

router.post("/fileInfo/load", async (ctx) => {
  //查询文件数据

  let body = {
    file: file,
    type: filetype,
    name: filename,
  };
  let buffer = Buffer.from(body.file, "binary"); //将文件数据转换为二进制
  ctx.body = {
    file: buffer,
    name: body.name,
    type: body.type,
  };
});

上传内容对应的base64

// 上传BASE64
app.post('/single2', (req, res) => {
    let {
        chunk,
        filename
    } = req.body;

    // chunk的处理:转换为buffer
    chunk = decodeURIComponent(chunk);
    chunk = chunk.replace(/^data:image\/\w+;base64,/, "");
    chunk = Buffer.from(chunk, 'base64');

    // 存储文件到服务器
    let spark = new SparkMD5.ArrayBuffer(),
        suffix = /\.([0-9a-zA-Z]+)$/.exec(filename)[1],
        path;
    spark.append(chunk);
    path = `${uploadDir}/${spark.end()}.${suffix}`;
    fs.writeFileSync(path, chunk);
    res.send({
        code: 0,
        originalFilename: filename,
        path: path.replace(__dirname, `http://127.0.0.1:${PORT}`)
    });
});

后端返回图片
方式一:返回图片在服务器中的地址
前端:

<template>
  <div class="main">
    <el-upload
      class="avatar-uploader"
      action="http://localhost:8888/uploadImg"
      :show-file-list="false"
      :http-request="upload"
    >
      <img v-if="imageUrl" :src="imageUrl" class="avatar" />
      <i v-else class="el-icon-plus avatar-uploader-icon"></i>
    </el-upload>
  </div>
</template>

<script>
export default {
  data() {
    return {
      imageUrl: ""
    };
  },
  methods: {
    upload(f) {
      console.log(f);
      let formData = new FormData();
      formData.append("file", f.file);

      this.$axios({
        method: "post",
        url: "http://localhost:8888/uploadImg",
        data: formData
      }).then(res => {
        //上传成功之后 显示图片
        this.imageUrl = res.data.fileSqlUrl ;
      });
    }
  }
};
</script>

<style></style>



后端:

const express = require("express");
const bodyParser = require("body-parser");
const app = express(); //返回一个服务
var mysql = require("mysql");
const path = require("path");
const path = require("path");
const multer = require("multer"); 
 // 以上需要 npm install 下载一下
var connection = mysql.createConnection({
  host: "120.77.****",
  user: "sqlroot",
  password: "*******",
  port: 3306,
  database: "sqlroot",
  useConnectionPooling: true,
}); 
connection.connect(function (err) {
  if (err) {
    console.log("error");
  }
  console.log("connect success!");
});
// 建立数据库连接
var fileSqlUrl = "http://localhost:8888/upLoad/";
var fileSqlName;
var storage = multer.diskStorage({
  //设置 上传图片服务器位置
  destination: path.resolve(__dirname, "./upload"),
  //设置 上传文件保存的文件名
  filename: function (req, file, cb) {
    // 获取后缀扩展
    let extName = file.originalname.slice(file.originalname.lastIndexOf(".")); //.jpg
    // 获取名称
    let fileName = Date.now();
    fileSqlName = fileName + extName;
    fileSqlUrl += fileSqlName;
    // console.log(fileName + extName); //12423543465.jpg
    cb(null, fileName + extName);
  },
});
var fileFilter = function (req, file, cb) {
  var acceptableMime = ["image/jpeg", "image/png", "image/jpg", "image/gif"];
  // 限制类型
  // null是固定写法
  if (acceptableMime.indexOf(file.mimetype) !== -1) {
    cb(null, true); // 通过上传
  } else {
    cb(null, false); // 禁止上传
  }
};
var limits = {
  fileSize: "10MB", //设置限制(可选)
};

const imageUploader = multer({
  fileFilter,
  storage,
  limits,
}).single("file"); //文件上传预定 name 或者 字段

// 图片
app.post("/uploadImg", imageUploader, (req, res) => {
  console.log(imageUploader);
  connection.query(
    `insert into img values(0,'${fileSqlUrl}','${fileSqlName}')`,
    (err, data) => {
      if (err) {
        res.send({ err: 1, msg: "增加数据失败", success: false });
        res.end();
      } else {
        res.send({ err: 0, msg: "添加成功", success: true, fileSqlUrl });
        res.end();
      }
    }
  );
});
app.use(express.static(__dirname + "/public"));

app.listen(8888, () => {
  console.log("服务已经启动");
});

后端返回视频方式
方式一:直接返回文件在服务器上的地址,和访问静态托管的资源方式一致

方式二:返回流(前端收到的即是blob,未验证)

//获取参数
    var params=urldeal.parse(req.url,true).query
    const ROOT_PATH = process.cwd();//必须使用绝对路径,使用相对路径会直接下载文件
    let path =ROOT_PATH+params.url;

    let stat = fs.statSync(path);  //获取文件信息
    let fileSize = stat.size;
    let range = req.headers.range;
	
	//206状态码表示的是:客户端通过发送范围请求头Range获取资源的部分数据。这种请求可以将服务端文件分割成多个部分传给客户端,
	//可用于解决网络问题以及大文件下载问题。对于一个很大的视频,就可以采用这种请求将视频流分成多个部分下载。 

    if (range) {
        //有range头才使用206状态码

        let parts = range.replace(/bytes=/, "").split("-");
        let start = parseInt(parts[0], 10);
        let end = parts[1] ? parseInt(parts[1], 10) : start + 9999999;

        // end 在最后取值为 fileSize - 1
        end = end > fileSize - 1 ? fileSize - 1 : end;

        let chunksize = (end - start) + 1;
        let file = fs.createReadStream(path, { start, end });
        let head = {
            'Content-Range': `bytes ${start}-${end}/${fileSize}`,
            'Accept-Ranges': 'bytes',
            'Content-Length': chunksize,
            'Content-Type': 'video/mp4',
        };
        res.writeHead(206, head);
        file.pipe(res);         //Node中的Server端HTTP response是Writable流
    } else {
        let head = {
            'Content-Length': fileSize,
            'Content-Type': 'video/mp4',
        };
        res.writeHead(200, head);
        fs.createReadStream(path).pipe(res);
    }

方式三:带有close监听的流

var fs = require("fs");

function readBigFileEntry(filename, response) {
  path.exists(filename, function (exists) {
    if (!filename || !exists) {
      response.writeHead(404);

      response.end();

      return;
    }

    var readStream = fs.ReadStream(filename);

    var contentType = "none";

    var ext = path.extname(filename);

    switch (ext) {
      case ".flv":
        contentType = "video/flv";

        break;
    }

    response.writeHead(200, {
      "Content-Type": contentType,

      "Accept-Ranges": "bytes",

      Server: "Microsoft-IIS/7.5",

      "X-Powered-By": "ASP.NET",
    });

    readStream.on("close", function () {
      response.end();

      console.log("Stream finished.");
    });

    readStream.pipe(response);
  });
}
===============================================
var express = require('express');
var pg = require('pg');
var app = express();
var fs = require('fs');
 
app.get('/video', function (req, res) {
    var time = new Date();
    var videoName = req.query.name;
    console.log("-------点击查询下载" + time.getFullYear() + "/" + time.getMonth() + "/" + time.getDate() + "/" + time.getHours() + "/" + time.getMinutes() + "/" + time.getSeconds() + "-------");
    res.writeHead(200, {'Content-Type': 'video/mp4'});
    var rs = fs.createReadStream(videoName + '.mp4');
    rs.pipe(res);
 
    rs.on('end', function () {
        res.end();
        console.log('end call');
    });
});
 
var server = app.listen(8081, function () {
 
    var host = server.address().address;
    var port = server.address().port;
 
    console.log("应用实例,访问地址为 http://%s:%s", host, port);
 
});

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>视频播放</title>
</head>
<body>
<video width="320" height="240" controls="controls">
    <source src="http://localhost:8081/video?name=123" type="video/mp4">
</video>
</body>
</html>
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值