內容:前端
1.文件上傳基礎node
2.node文件處理機制後端
3.用流實現文件上傳post
1.文件上傳基礎ui
前端代碼:加密
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
後端代碼:spa
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.丟棄掉每一個數據頭尾的"\r\n" 32 arr = arr.map(buffer => buffer.slice(2, buffer.length - 2)); 33 34 //4.每一個數據在第一個"\r\n\r\n"處切成兩半 35 arr.forEach(buffer => { 36 let n = buffer.indexOf('\r\n\r\n'); 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('\r\n') === -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"\r\n 55 Content-Type: text/plain*/ 56 let [line1, line2] = disposition.split('\r\n'); 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文件處理機制code
node文件上傳從根本上來講就兩種方法:orm
(1)最基礎原始的方法server
使用fs中的readFile和writeFile實現(讀取完上傳的文件後保存)
這樣作有弊端:
(2)更好的方法
使用流,收到一部分數據就直接解析一部分,實例見後面的文件上傳實例
3.用流實現文件上傳
(1)流
三種流:
(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 }