JavaScript中的FileReader示例詳解
前言:
FileReader是一種異步文件讀取機制,結合input:file可以很方便的讀取本地文件。
input:file
在介紹FileReader之前,先簡單介紹input的file類型。
<input type="file" id="file">
input的file類型會渲染為一個按鈕和一段文字。點擊按鈕可打開文件選擇窗口,文字表示對文件的描述(大部分情況下為文件名);file類型的input會有files屬性,保存著文件的相關信息。
document.querySelector('#file').addEventListener('change',(fileChoosed) => { console.log('fileChoosed', fileChoosed.target.files) })
點擊按鈕上傳一個文件後,在控制臺打印上傳的文件信息,如下:
可以發現文件信息是一個json對象,由傳入的file對象組成。每個file對象(即每個上傳文件)包含以下屬性:
lastModified:數值,表示最近一次修改時間的毫秒數;
lastModifiedDate:對象,表示最近一次修改時間的Date對象;
name:本地文件系統中的文件名;
size:文件的字節大小;
type:字符串,文件的MIME類型;
webkitRelativePath:此處為空;當在input上加上webkitdirectory屬性時,用戶可選擇文件夾,此時webkitRelativePath表示文件夾中文件的相對路徑。
<input type="file" id="file" webkitdirectory>
FileReader
以上file對象隻獲取到瞭對文件的描述信息,但沒有獲得文件中的數據。我們可以通過html5提供的FileReader讀取到文件中的數據。
首先創建一個FileReader實例:
const reader = new FileReader();
FileReader提供瞭如下方法:
readAsArrayBuffer(file)
按字節讀取文件內容,結果用ArrayBuffer對象表示
readAsBinaryString(file)
按字節讀取文件內容,結果為文件的二進制串
readAsDataURL(file)
讀取文件內容,結果用data:url的字符串形式表示
readAsText(file,encoding)
按字符讀取文件內容,結果用字符串形式表示
abort()
終止文件讀取操作
readAsDataURL和readAsText較為常用,這裡隻對這兩者進行說明。
readAsDataURL會將文件內容進行base64編碼後輸出:
document.querySelector('#file').addEventListener('change',(fileChoosed) => { const reader = new FileReader(); reader.readAsDataURL(fileChoosed.target.files[0]);//發起異步請求 reader.onload = function(readRes){ console.log('加載完成', readRes.target.result) } })
控制臺為當前所傳文件的base64編碼表示。由於媒體文件的src屬性,可以通過采用網絡地址或base64的方式顯示,因此我們可以利用readAsDataURL實現對圖片的預覽。
如下,隻需將讀取的結果賦給圖片的src屬性,即可預覽圖片:
<input type="file" id="file" /> <img src="" id="imgPreview">
document.querySelector('#file').addEventListener('change',(fileChoosed) => { const reader = new FileReader(); reader.readAsDataURL(fileChoosed.target.files[0]);//發起異步請求 reader.onload = function(readRes){ document.querySelector('#imgPreview').src = readRes.target.result } })
readAsText可按指定編碼方式讀取文件,但讀取文件的單位是字符,故對於文本文件,隻要按規定的編碼方式讀取即可;而對於媒體文件(圖片、音頻、視頻),其內部組成並不是按字符排列,故采用readAsText讀取,會產生亂碼。
FileReader事件:
- onloadstart 當讀取操作開始時調用
- onprogress 在讀取數據過程中周期性調用
- onabort 當讀取操作被中止時調用
- onerror 當讀取操作發生錯誤時調用
- onload 當讀取操作成功完成時調用
- onloadend 當讀取操作完成時調用,無論成功,失敗或取消
註釋:
- 每過50ms左右,就會觸發一次progress事件,對於較大的文件可以利用progress實現進度條;
- 由於種種原因無法讀取文件時,會觸發error事件。觸發error事件時,相關信息保存在FileReader對象的error屬性中,這個屬性將保存一個對象,此對象隻有一個屬性code,即錯誤碼。1表示未找到文件,2表示安全性錯誤,3表示讀取中斷,4表示文件不可讀,5表示編碼錯誤。
示例:
<input type="file" id="file" />
document.querySelector('#file').addEventListener('change',(fileChoosed) => { const reader = new FileReader(); reader.readAsText(fileChoosed.target.files[0],'utf-8');//發起異步請求 reader.onloadstart = function(readRes){ // 文件大於500kb則取消加載 if(readRes.total > 1024*500) { reader.abort() } else { console.log("開始加載") } } reader.onabort = function (readRes) { console.log('加載已取消') } reader.onprogress = function(readRes){ console.log("加載中", `${(readRes.loaded / readRes.total).toFixed(2)*100}/100`) }
補充:一個比較全面的例子
實現的功能:
- 通過file控件預覽文本, 圖片
- 非文本, 圖片的以二進制串輸出
- 拖拽上述文件實現預覽
包含的知識點:
- readAsText方法的使用
- readAsDataURL方法的使用
- readAsBinaryString方法的使用
- 一些Promise的用法也穿插其中
- 簡單的拖拽用法
為瞭方便觀看, 這裡也把代碼帖上:
<!DOCTYPE html> <html lang="zh-CN"> <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>FileReader Learning</title> </head> <body> <div class="container"> <form novalidate> <div class="avatars-row" style="margin: 10px;"> <label>選擇文件: <input type="file" name="avatars" id="attachment" accept="*/*" multiple></input> </label> </div> <div class="result" id="result" style="overflow: auto; border: 1px solid cyan; height: 300px;"></div> </form> </div> <script> (function (window, doc, undefined) { function $(id) { return doc.getElementById(id); } let App = { createFileReader: () => { if (typeof FileReader === "undefined") { throw new Error("FileReader is not avaliable"); } return new FileReader(); }, /** * @return FileList */ getFiles: () => { var attachment = $("attachment"), files = attachment.files; return files || new Error("no file uploaded"); }, /** * 統一的讀取接口 */ read: function(api, file, callback) { let self = this; return new Promise((resolve, reject) => { let reader = self.createFileReader(); reader.onload = e => { resolve(e.target.result); }; reader.onerror = e => { reject("read error"); }; reader.onabort = e => { reject("abort error"); }; // size <= 1M if (file && file.size > 1 * 1024 * 1024) { reject('file is too large'); return; } reader[api](file); }); }, onFileChange: function(callback) { let self = this; $("attachment").onchange = function (e) { callback(self.getFiles()); }; }, onDrop: function() { let self = this; let resultContainer = $('result'); document.ondragover = e => { e.preventDefault(); }; document.ondrop = e => { e.preventDefault(); }; resultContainer.ondragend = e => { e.preventDefault(); }; resultContainer.ondrop = e => { e.preventDefault(); let files = e.dataTransfer.files; self.handleAll(files); }; }, handleFiles: function(files) { let self = this; let p; let ret = []; // FileList轉數組 [].slice.call(files).forEach(function(file, i) { const type = file.type; switch (true) { case /text\/\w+/.test(type): p = self.read("readAsText", file); break; case /image\/\w+/.test(type): p = self.read("readAsDataURL", file); break; default: p = self.read("readAsBinaryString", file); break; } ret.push(p); }); return ret; }, init: function() { var self = this; self.onDrop(); // 這裡的onFileChange不能寫成Promise, 不然隻會第一次有效, 因為狀態已經是fulfilled瞭 self.onFileChange(files => { self.handleAll(files); }); }, handleAll: function(files) { let self = this; Promise.all(self.handleFiles(files)) .then(results => { self.showResults(results); }) .catch(err => { console.log(err); }); }, showResults: results => { console.log(results); let resultContainer = $("result"); results.forEach((result, i) => { // alert(3); switch (true) { case result.indexOf("data:image/") >= 0: resultContainer.innerHTML += `<div><img src="${result}"></div>`; break; default: resultContainer.innerHTML += `<p>${result}<p>`; break; } }); } }; App.init(); })(window, document); </script> </body> </html>
總結
到此這篇關於JavaScript中FileReader的文章就介紹到這瞭,更多相關js中的FileReader內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- JS使用base64格式上傳文件
- js前端上傳文件縮略圖技巧示例詳解
- Blob對象實現文件上傳下載示例詳解
- JS中URL.createObjectURL使用示例講解
- JavaScript中各種二進制對象關系的深入講解