zoukankan      html  css  js  c++  java
  • node进阶之用流实现上传文件

    内容:

    1.文件上传基础

    2.node文件处理机制

    3.用流实现文件上传

    1.文件上传基础

    前端代码:

    1 <form action="localhost:8080/" method="post" enctype="multipart/form-data">
    2     <input type="file" name="f1">
    3     <input type="submit" value="上传文件">
    4 </form>
    5 
    6 注意:
    7     上传文件时表单中的enctype="multipart/form-data"必须要写
    8     input(file)必须要有name

    后端代码:

     1 const http = require('http');
     2 const uuid = require('uuid/v4');
     3 const fs = require('fs')
     4 
     5 let server_post = http.createServer((req, res) => {
     6     let arr = [];
     7 
     8     req.on('data', data => {
     9         arr.push(data);
    10     });
    11     req.on('end', () => {
    12         let data = Buffer.concat(arr);
    13         // console.log(data)
    14 
    15         //data
    16         //解析二进制文件上传数据
    17         let post = {};
    18         let files = {};
    19         if (req.headers['content-type']) {
    20             let str = req.headers['content-type'].split('; ')[1];
    21             if (str) {
    22                 let boundary = '--' + str.split('=')[1];
    23 
    24                 //1.用"分隔符切分整个数据"
    25                 let arr = (data.toString()).split(boundary);
    26 
    27                 //2.丢弃头尾两个数据
    28                 arr.shift();
    29                 arr.pop();
    30 
    31                 //3.丢弃掉每个数据头尾的"
    "
    32                 arr = arr.map(buffer => buffer.slice(2, buffer.length - 2));
    33 
    34                 //4.每个数据在第一个"
    
    "处切成两半
    35                 arr.forEach(buffer => {
    36                     let n = buffer.indexOf('
    
    ');
    37 
    38                     let disposition = buffer.slice(0, n);
    39                     let content = buffer.slice(n + 4);
    40 
    41                     disposition = disposition.toString();
    42 
    43                     if (disposition.indexOf('
    ') === -1) {
    44                         //普通数据
    45                         //Content-Disposition: form-data; name="user"
    46                         content = content.toString();
    47 
    48                         let name = disposition.split('; ')[1].split('=')[1];
    49                         name = name.substring(1, name.length - 1);
    50 
    51                         post[name] = content;
    52                     } else {
    53                         //文件数据
    54                         /*Content-Disposition: form-data; name="f1"; filename="a.txt"
    
    55                         Content-Type: text/plain*/
    56                         let [line1, line2] = disposition.split('
    ');
    57                         let [, name, filename] = line1.split('; ');
    58                         let type = line2.split(': ')[1];
    59 
    60                         name = name.split('=')[1];
    61                         name = name.substring(1, name.length - 1);
    62                         filename = filename.split('=')[1];
    63                         filename = filename.substring(1, filename.length - 1);
    64 
    65                         let path = `upload/${uuid().replace(/-/g, '')}`;
    66 
    67                         fs.writeFile(path, content, err => {
    68                             if (err) {
    69                                 console.log('文件写入失败', err);
    70                             } else {
    71                                 files[name] = {filename, path, type};
    72                                 console.log(files);
    73                             }
    74                         });
    75                     }
    76                 });
    77 
    78 
    79                 //5.完成
    80                 console.log(post);
    81             }
    82         }
    83 
    84 
    85         res.end();
    86     });
    87 });
    88 server_post.listen(8080);

    2.node文件处理机制

    node文件上传从根本上来说就两种方法:

    (1)最基础原始的方法

    使用fs中的readFile和writeFile实现(读取完上传的文件后保存)

    这样做有弊端:

    • 只能等到所有数据都到达了才开始处理
    • readFile先把所有数据全读到内存中,然后回调:
    • 1.极其占用内存
    • 2.资源利用极其不充分

    (2)更好的方法

    使用流,收到一部分数据就直接解析一部分,实例见后面的文件上传实例

    3.用流实现文件上传

    (1)流

    三种流:

    • 读取流  -->  fs.createReadStream、req
    • 写入流  -->  fs.createWriteStream、res
    • 读写流  -->  压缩、加密

    (2)流实现读写文件

     1 const fs = require('fs')
     2 
     3 let rs = fs.createReadStream('1.txt')       // 读取流
     4 let ws = fs.createWriteStream('2.txt')      // 写入流
     5 
     6 rs.pipe(ws)
     7 
     8 // 异常处理
     9 rs.on('error', function (error) {
    10     console.log('读取失败!')
    11 })
    12 
    13 // 读取完成 及 写入完成
    14 rs.on('end', function () {
    15     console.log('读取完成!')
    16 })
    17 
    18 ws.on('finish', function () {
    19     console.log('写入完成!')
    20 })

    注:1.txt应该在同级目录下

    (3)用流实现上传文件核心代码

     1 /**
     2  * [saveFileWithStream description]
     3  * @param {String} filePath [文件路径]
     4  * @param {Buffer} readData [Buffer 数据]
     5  */
     6 static saveFile(filePath, fileData) {
     7  return new Promise((resolve, reject) => {
     8   // 块方式写入文件
     9   const wstream = fs.createWriteStream(filePath);
    10  
    11   wstream.on('open', () => {
    12    const blockSize = 128;
    13    const nbBlocks = Math.ceil(fileData.length / (blockSize));
    14    for (let i = 0; i < nbBlocks; i += 1) {
    15     const currentBlock = fileData.slice(
    16      blockSize * i,
    17      Math.min(blockSize * (i + 1), fileData.length),
    18     );
    19     wstream.write(currentBlock);
    20    }
    21  
    22    wstream.end();
    23   });
    24   wstream.on('error', (err) => { reject(err); });
    25   wstream.on('finish', () => { resolve(true); });
    26  });
    27 }
    28 
    29 // 实际调用的时候,如下:
    30 try {
    31  await saveFileWithStream(filePath, fileData); // 这里的fileData是Buffer类型
    32 } catch (err) {
    33  console.log(err.stack);
    34 }
  • 相关阅读:
    OK335x mksd.sh hacking
    Qt jsoncpp 对象拷贝、删除、函数调用 demo
    OK335xS 256M 512M nand flash make ubifs hacking
    Qt QScrollArea and layout in code
    JsonCpp Documentation
    Qt 4.8.5 jsoncpp lib
    Oracle数据库生成UUID
    freemarker得到数组的长度
    FreeMarker中if标签内的判断条件
    freemarker语法
  • 原文地址:https://www.cnblogs.com/wyb666/p/9694481.html
Copyright © 2011-2022 走看看