項目目錄:javascript
1.上傳單個文件html
思路:java
(1)獲取上傳文件,使用 const file = ctx.request.files.fileios
(2)咱們使用 fs.createReadStream 來讀取文件流;如代碼:const fileReader = fs.createReadStream(file.path); axios
(3)對當前上傳的文件保存到 /static/upload 目錄下,所以定義變量:const filePath = path.join(__dirname, '/static/upload/');數組
(4) 組裝文件的絕對路徑,代碼:const fileResource = filePath + `/${file.name}`;app
(5)使用 fs.createWriteStream 把該文件寫進去,如代碼:const writeStream = fs.createWriteStream(fileResource);koa
(6) 下面這段代碼就是判斷是否有該目錄,若是沒有改目錄,就建立一個 /static/upload 這個目錄,若是有就直接使用管道流pipe拼接文件,如代碼:fileReader.pipe(writeStream);post
if (!fs.existsSync(filePath)) { fs.mkdir(filePath, (err) => { if (err) { throw new Error(err); } else { fileReader.pipe(writeStream); ctx.body = { url: uploadUrl + `/${file.name}`, code: 0, message: '上傳成功' }; } }); } else { fileReader.pipe(writeStream); ctx.body = { url: uploadUrl + `/${file.name}`, code: 0, message: '上傳成功' }; }
最後咱們使用 ctx.body 返回到頁面來,所以若是咱們上傳成功了,就會在upload頁面返回以下信息了;以下圖所示:ui
源碼:
static/upload.html
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>文件上傳</title> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <!-- 使用form表單提交 <form action="http://localhost:3001/upload" method="post" enctype="multipart/form-data"> <div> <input type="file" name="file"> </div> <div> <input type="submit" value="提交"/> </div> </form> --> <div> <input type="file" name="file" id="file"> </div> <script type="text/javascript"> var file = document.getElementById('file'); const instance = axios.create({ withCredentials: true }); file.onchange = function(e) { var f1 = e.target.files[0]; var fdata = new FormData(); fdata.append('file', f1); instance.post('http://localhost:3001/upload', fdata).then(res => { console.log(res); }).catch(err => { console.log(err); }); } </script> </body> </html>
app.js
// 引入模塊 const Koa = require('koa'); const fs = require('fs'); const path = require('path'); const router = require('koa-router')(); const koaBody = require('koa-body'); const static = require('koa-static'); // 實例化 const app = new Koa(); app.use(koaBody({ multipart: true, // 支持文件上傳 formidable: { maxFieldsSize: 2 * 1024 * 1024, // 最大文件爲2兆 multipart: true // 是否支持 multipart-formdate 的表單 } })); const uploadUrl = "http://localhost:3001/static/upload"; // 配置路由 router.get('/', (ctx) => { // 設置頭類型, 若是不設置,會直接下載該頁面 ctx.type = 'html'; // 讀取文件 const pathUrl = path.join(__dirname, '/static/upload.html'); ctx.body = fs.createReadStream(pathUrl); }); // 上傳文件 router.post('/upload', (ctx) => { // 獲取上傳文件 const file = ctx.request.files.file; console.log(file); // 讀取文件流 const fileReader = fs.createReadStream(file.path); console.log(fileReader); // 設置文件保存路徑 const filePath = path.join(__dirname, '/static/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: uploadUrl + `/${file.name}`, code: 0, message: '上傳成功' }; } }); } else { fileReader.pipe(writeStream); ctx.body = { url: uploadUrl + `/${file.name}`, code: 0, message: '上傳成功' }; } }); // 配置靜態資源路徑 app.use(static(path.join(__dirname))); // 啓動路由 app.use(router.routes()).use(router.allowedMethods()); // 監聽端口號 app.listen(3001, () => { console.log('server is listen in 3001'); });
2.上傳多個文件
爲了支持多個文件上傳,和單個文件上傳,咱們須要把代碼改下,改爲以下:
static/upload.html
<!DOCTYPE html> <html> <head> <meta charset=utf-8> <title>文件上傳</title> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> </head> <body> <!-- 使用form表單提交 <form action="http://localhost:3001/upload" method="post" enctype="multipart/form-data"> <div> <input type="file" name="file"> </div> <div> <input type="submit" value="提交"/> </div> </form> --> <!-- 上傳單個文件 <div> <input type="file" name="file" id="file"> </div> <script type="text/javascript"> var file = document.getElementById('file'); const instance = axios.create({ withCredentials: true }); file.onchange = function(e) { var f1 = e.target.files[0]; var fdata = new FormData(); fdata.append('file', f1); instance.post('http://localhost:3001/upload', fdata).then(res => { console.log(res); }).catch(err => { console.log(err); }); } </script> --> <div> <input type="file" name="file" id="file" multiple="multiple"> </div> <script type="text/javascript"> var file = document.getElementById('file'); const instance = axios.create({ withCredentials: true }); file.onchange = function (e) { var files = e.target.files; var fdata = new FormData(); if (files.length > 0) { for (let i = 0; i < files.length; i++) { const f1 = files[i]; fdata.append('file', f1); } } instance.post('http://localhost:3001/upload', fdata).then(res => { console.log(res); }).catch(err => { console.log(err); }); } </script> </body> </html>
如上是多個文件上傳的html代碼和js代碼,就是把多個數據使用formdata一次性傳遞多個數據過去,如今咱們須要把app.js 代碼改爲以下了,app.js 代碼改的有點多,最主要是要判斷 傳過來的文件是單個的仍是多個的邏輯,全部代碼以下:
// 引入模塊 const Koa = require('koa'); const fs = require('fs'); const path = require('path'); const router = require('koa-router')(); const koaBody = require('koa-body'); const static = require('koa-static'); // 實例化 const app = new Koa(); app.use(koaBody({ multipart: true, // 支持文件上傳 formidable: { maxFieldsSize: 2 * 1024 * 1024, // 最大文件爲2兆 multipart: true // 是否支持 multipart-formdate 的表單 } })); const uploadUrl = "http://localhost:3001/static/upload"; router.get('/', (ctx) => { // 設置頭類型, 若是不設置,會直接下載該頁面 ctx.type = 'html'; // 讀取文件 const pathUrl = path.join(__dirname, '/static/upload.html'); ctx.body = fs.createReadStream(pathUrl); }); /** * flag: 是不是多個文件上傳 */ const uploadFilePublic = function (ctx, files, flag) { const filePath = path.join(__dirname, '/static/upload/'); let file, fileReader, fileResource, writeStream; const fileFunc = function (file) { // 讀取文件流 fileReader = fs.createReadStream(file.path); // 組裝成絕對路徑 fileResource = filePath + `/${file.name}`; /* 使用 createWriteStream 寫入數據,而後使用管道流pipe拼接 */ writeStream = fs.createWriteStream(fileResource); fileReader.pipe(writeStream); }; const returnFunc = function (flag) { console.log(flag); console.log(files); if (flag) { let url = ''; for (let i = 0; i < files.length; i++) { url += uploadUrl + `/${files[i].name},` } url = url.replace(/,$/gi, ""); ctx.body = { url: url, code: 0, message: '上傳成功' }; } else { ctx.body = { url: uploadUrl + `/${files.name}`, code: 0, message: '上傳成功' }; } }; if (flag) { // 多個文件上傳 for (let i = 0; i < files.length; i++) { const f1 = files[i]; fileFunc(f1); } } else { fileFunc(files); } // 判斷 /static/upload 文件夾是否存在,若是不在的話就建立一個 if (!fs.existsSync(filePath)) { fs.mkdir(filePath, (err) => { if (err) { throw new Error(err); } else { returnFunc(flag); } }); } else { returnFunc(flag); } } // 上傳單個或多個文件 router.post('/upload', (ctx) => { let files = ctx.request.files.file; const fileArrs = []; if (files.length === undefined) { // 上傳單個文件,它不是數組,只是單個的對象 uploadFilePublic(ctx, files, false); } else { uploadFilePublic(ctx, files, true); } }); // 配置靜態資源路徑 app.use(static(path.join(__dirname))); // 啓動路由 app.use(router.routes()).use(router.allowedMethods()); // 監聽端口號 app.listen(3001, () => { console.log('server is listen in 3001'); });
而後我如今來演示下,當我選擇多個文件,好比如今選擇兩個文件,會返回以下數據:
當我如今只選擇一個文件的時候,只會返回一個文件,以下圖所示:
如上app.js改爲以後的代碼如今支持單個或多個文件上傳了。
轉自:https://www.cnblogs.com/tugenhua0707/p/10828869.html
.