NodeJs之文件上傳
一,介紹與需求
1.1,介紹
1,multer模塊
multer用於處理文件上傳的nodejs中間件,主要跟express框架搭配使用,只支持表單MIME編碼為multipart/form-data類型的數據請求.
2,fs模塊
fs模塊用於對系統文件及目錄進行讀寫操作。
1.2,需求
上傳並操作文件與文件目錄
二,配置實現
2.1,multer模塊
第一步:安裝multer模塊
1 cnpm install multer --save
第二步:引入multer模塊,構造multer對象: multer(opt)
opt是個key-value對象,包含屬性dest/storage,fileFilter,limits.分表表示文件的存儲位置/方式,文件過濾,文件大小限制.如下:
1 var moment = require("moment"); 2 var express = require("express"); 3 var multer = require('multer'); 4 var storage = multer.diskStorage({ 5 //文件存儲路徑 6 destination: function (req, file, cb) { 7 cb(null, path.join(__dirname, "/../uploads/temps")); 8 }, 9 //修改上傳文件的名字 10 //file 是個文件對象 ,fieldname對應在客戶端的name屬性 11 //存儲的文件需要自己加上文件的后綴,multer並不會自動添加 12 //這里直接忽略文件的后綴. 13 filename: function (req, file, cb) { 14 var date = new Date(); 15 cb(null, moment().format("YYYYMMDDhhmmss") + file.originalname); 16 } 17 }); 18 let objMulter = multer({storage : storage });
如果初始化multer時候沒有指定dest或者storage,上傳的文件將保存在內存中,永遠不會寫入到磁盤中,在storage中如果沒有指定destination值,那么上傳的文件將存儲在系統默認的臨時文件夾.
1 multer關聯的文件信息: 2 3 filedname : 在form表單中指定的name屬性值 4 orginalname : 原始文件名 5 encoding : 文件編碼方式 6 mimetype : 多媒體類型 7 size : 文件大小,單位b 8 destination : 文件上傳后存儲在服務端的路徑 9 filename : 文件在服務端的命名 10 path : 文件在服務端的完整路徑 11 buffer : 文件二進制數據 12 13 ps:其中destination,filename和path只有在指定storage屬性時候有效.而buffer只有文件在內存中存儲時候有效.
multer同時提供了single/array/fields/any方法用於對接受文件數的控制.
- single(fieldname) 接收單個文件,通過req.file訪問該文件
- array(fieldnaem,[maxcount]) 接收多個文件,通過req.files數組方法文件.maxcount指定接收文件最大數.
- fields(fields) 接受指定fieldname的文件,fieldname由客戶端決定,通過req.files數組方法
- any 接收所有文件上傳,通過req.files訪問文件
2.2,fs模塊
第一步:安裝fs模塊,也可直接引用,node默認集成
1 cnpm install fs --save//項目目錄安裝 2 var fs = require("fs");//直接引入文件系統模塊
第二步:介紹fs模塊的方法
1 var fs = require('fs'); // 載入fs模塊
1,刪除指定文件:fs.unlink(path,callback)
path
參數為該文件的絕對物理路徑,callback
回調參數當中只有一個錯誤信息參數err
,一般在該文件不存在或者刪除文件失敗時觸發調用。
1 fs.unlink('/tmp/234.txt', function(err) { 2 if (err) { 3 throw err; 4 } 5 console.log('成功刪除了 /tmp/234.txt'); 6 });
2,讀取文件:fs.readFile(filename,[option],callback)
參數說明:
-
- filename String 文件名
- option Object
- encoding String |null default=null
- flag String default='r'
- callback Function
path
參數為該文件的絕對物理路徑,其中options
參數可選,可以傳入編碼格式,如讀取文本文件時,可傳入'utf8'
,若不指定編碼格式,則默認輸出讀取的文件內容為Buffer
形式,故一般都會傳入該參數。callbac
k回調參數當中有兩個參數err
和data
,其中err
為錯誤信息參數,一般在在文件不存在或者讀取文件失敗時觸發調用,data
為文件內容。
1 fs.readFile('./tmp/test.txt','utf-8'function(err, data) {
2 // 讀取文件失敗/錯誤
3 if (err) {
4 throw err;
5 }
6 // 讀取文件成功
7 console.log(data);
8 });
3,寫入文件:fs.writeFile(filename,data,[options],callback),追加寫入:
fs.appendFile(filename,data[,options],callback)
filename參數為該文件的絕對物理路徑,data
為需要寫入該文件當中的數據內容,其中options
參數可選,可以傳入編碼格式,若不傳則默認為utf8
。callback
回調參數當中只有一個錯誤信息參數err
,一般在寫入失敗時觸發調用。
1 // 寫入文件內容(如果文件不存在會創建一個文件) 2 // 傳遞了追加參數 { 'flag': 'a' } 3 fs.writeFile('./test2.txt', 'test test', { 'flag': 'a' }, function(err) { 4 if (err) { 5 throw err; 6 } 7 8 console.log('Saved.'); 9 10 // 寫入成功后讀取測試 11 fs.readFile('./test2.txt', 'utf-8', function(err, data) { 12 if (err) { 13 throw err; 14 } 15 console.log(data); 16 }); 17 });
flag傳值,r代表讀取文件,w代表寫文件,a代表追加。
1 // 追加寫入 2 fs.appendFile("2.txt","我是追加的字符",function (err) { 3 if(err){ 4 return console.log(err); 5 }else { 6 console.log("追加成功"); 7 } 8 })
4,檢測文件是否存在:fs.exists(path,callback)
path
參數傳入該文件的絕對物理路徑,該callback
回調函數有個參數exists。exists為一個文件狀態對象,是否存在。
1 var dest_Dir = path.join(__dirname.replace("routes", ""), "uploads", destDir); 2 fs.exists(dest_Dir, function (exists) { 3 if (exists) { 4 //存在 5 } 6 else { 7 8 } 9 });
5,移動或重命名指定文件:fs.rename(oldPath,newPath,callback)
oldPath
參數為該文件原來的路徑,newPath
參數為該文件移動或重命名之后的路徑,這兩個參數都必須能傳入文件完整的絕對物理路徑。callback
回調參數當中只有一個錯誤信息參數,一般在oldPath
當中指定的文件不存在或者該操作失敗時觸發調用。
1 fs.rename(sourceFile, destPath, function (err) { 2 res.status(200).json({ 3 httpCode: 200, 4 message: '上傳成功', 5 data: { 6 "fileurl": fileurl 7 }, 8 }); 9 });
6,創建一個目錄文件夾:fs.mkdir(path[,model],callback)
path
為該目錄的絕對物理路徑,callback
回調函數當中也只有一個錯誤信息參數,一般在目錄創建失敗時觸發調用。
1 fs.mkdir(dest_Dir, 0777, function (err) { 2 if (err) { 3 res.status(500).json({ 4 5 } else { 6 //創建目錄成功,上傳文件 7 fs.rename(sourceFile, destPath, function (err) { 8 res.status(200).json({ 9 httpCode: 200, 10 message: '上傳成功', 11 data: { 12 "fileurl": fileurl 13 }, 14 }); 15 }); 16 } 17 })
7,讀取目錄文件夾:fs.readdir(path,callback)
path
為該目錄的絕對物理路徑,callback
回調函數當中有兩個參數err
和files
,err
為錯誤信息參數,一般在該目錄不存在或讀取失敗時觸發調用,files
為一個數組對象,包含該目錄下的所有文件夾與文件的名字。(僅為文件夾的名字和文件名,不是路徑形式)。
1 fs.readdir('./newdir', function(err, files) { 2 if (err) { 3 throw err; 4 } 5 // files是一個數組 6 // 每個元素是此目錄下的文件或文件夾的名稱 7 console.log(files); 8 });
8,刪除一個空文件夾:fs.rmdir(path,callback)
path
為該目錄的絕對物理路徑,callback
回調函數當中也只有一個錯誤信息參數,一般在該目錄不存在或者刪除操作失敗時觸發調用。
1 fs.rmdir('/tmp', function(err) { 2 if (err) { 3 throw err; 4 } 5 console.log('成功刪除了 空文件夾 tmp'); 6 });
以上的實例均是異步操作,如果需同步操作在函數后面加Sync既可
1 //同步 所有同步的函數都是函數后面加Sync; 2 var res = fs.writeFileSync("1.txt","我是寫入內容");
2.3,文件上傳
1,單文件上傳
1 router.post('/upload', upload.single('file'), function (req, res, next) { 2 var fileName = req.file.filename; 3 var destDir = req.body.dir == undefined ? "default" : req.body.dir; 4 var sourceFile = req.file.path; 5 var destPath = path.join(__dirname.replace("routes", ""), "uploads", destDir, fileName); 6 var dest_Dir = path.join(__dirname.replace("routes", ""), "uploads", destDir); 7 var fileurl = uploadFileDomin + destPath.substr(destPath.indexOf("uploads")); 8 fileurl = fileurl.replace(/\\/g, "/"); 9 fs.exists(dest_Dir, function (exists) { 10 if (exists) { 11 fs.rename(sourceFile, destPath, function (err) { 12 res.status(200).json({ 13 httpCode: 200, 14 message: '上傳成功', 15 data: { 16 "fileurl": fileurl 17 }, 18 }); 19 }); 20 } 21 else { 22 fs.mkdir(dest_Dir, 0777, function (err) { 23 if (err) { 24 res.status(500).json({ 25 httpCode: 500, 26 message: err, 27 data: [], 28 }); 29 } else { 30 fs.rename(sourceFile, destPath, function (err) { 31 res.status(200).json({ 32 httpCode: 200, 33 message: '上傳成功', 34 data: { 35 "fileurl": fileurl 36 }, 37 }); 38 }); 39 } 40 }) 41 } 42 }); 43 44 });
2,多文件上傳
1 router.post('/uploads', upload.array('file', 8), function (req, res, next) { 2 var paths = []; 3 for (var i = 0; i < req.files.length; i++) { 4 var path = req.files[i].path.replace(/\\/g, "/"); 5 var fileurl = uploadFileDomin + path.substr(path.indexOf("uploads")).replace('\\', '/'); 6 paths.push(fileurl); 7 } 8 res.status(200).json({ 9 httpCode: 200, 10 message: '上傳成功', 11 "fileurls": paths, 12 }); 13 });
最后拋出發送上傳接口:
1 app.use("/api", require("./fileUploadApi.js"));
三,前端調用
3.1,單文件上傳調用
1,簡單html
1 <span>ajax upload</span> 2 <div class="container"> 3 <label>file</label> 4 <input type="file" name="file" id="file"> 5 <input type='button' value='上傳' id="btn_upload" /> 6 </div>
2,js調用
1 $("#btn_upload").click(function () { 2 //創建一個FormDate 3 var formData = new FormData(); 4 //將文件信息追加到其中 5 formData.append('file', file.files[0]); 6 formData.append('dir', 'attachment'); 7 //formData.append('name', file.files[0].name); 8 $.ajax({ 9 url: "http://localhost:3000/api/" + 'upload', 10 type: 'POST', 11 data: formData, 12 cache: false, 13 contentType: false, 14 processData: false, 15 xhrFields: { 16 withCredentials: true 17 }, 18 crossDomain: true, 19 success: function (data) { 20 callBack(data); 21 }, 22 error: function (response) { 23 console.log("error is :" + response); 24 } 25 });
3,實現效果
3.2,多文件上傳調用
1,簡單html
1 <span>ajax multi files upload</span> 2 <div class="container"> 3 <label>file</label> 4 <input type="file" name="file" id="files1"> 5 <input type="file" name="file" id="files2"> 6 <input type="file" name="file" id="files3"> 7 <input type='button' value='上傳' id="btn_uploads" /> 8 </div>
2,js調用
1 var files1 = $("#files1")[0]; 2 var files2 = $("#files2")[0]; 3 var files3 = $("#files3")[0]; 4 $("#btn_uploads").click(function () { 5 //創建一個FormDate 6 var formData = new FormData(); 7 //將文件信息追加到其中 8 formData.append('file', files1.files[0]); 9 formData.append('file', files2.files[0]); 10 formData.append('file', files3.files[0]); 11 $.ajax({ 12 url: 'http://localhost:3000/api/' + 'uploads', 13 type: 'POST', 14 data: formData, 15 contentType: false, 16 processData: false, 17 async: false, 18 xhrFields: { 19 withCredentials: true 20 }, 21 crossDomain: true, 22 success: function (data) { 23 callBack(data.fileurls); 24 }, 25 error: function (response) { 26 console.log("error is :" + response); 27 } 28 }) 29 })
3,實現效果