HTML5新特性之檔案和二進位制資料的操作
歷史上,JavaScript無法處理二進位制資料。如果一定要處理的話,只能使用charCodeAt()方法,一個個位元組地從文字編碼轉成二進位制資料,還有一種辦法是將二進位制資料轉成Base64編碼,再進行處理。這兩種方法不僅速度慢,而且容易出錯。ECMAScript5引入了Blob物件,允許直接操作二進位制資料。
Bolb物件是一個代表二進位制資料的基本物件,在它的基礎上,又衍生出一系列相關的API,用來操作檔案。
- File物件:負責處理那些以檔案形式存在的二進位制資料,也就是操作本地檔案
- FileList物件:File物件的網頁表單介面
- FileReader物件:負責將二進位制資料讀入記憶體
- URL物件:用於對二進位制資料生成URL
1、Blob物件
Blob(Binary Large Object)物件代表了一段二進位制資料,提供了一系列操作介面。其他操作二進位制資料的API(比如File物件),都是建立在Blob物件基礎上的,繼承了它的屬性和方法。
生成Blob物件有兩種方法:一種是使用Blob建構函式,另一種是對現有的Blob物件使用slice方法切出一部分。
(1)Blob建構函式,接受兩個引數。第一個引數是一個包含實際資料的陣列,第二個引數是資料的型別,這兩個引數都不是必需的。
var htmlParts = ['<a id="a"><b id="b">hey!<\/b><\/a>'];var myBlob = new Blob(htmlParts, {'type': 'text\/xml'});
下面是一個利用Blob物件,生成可下載檔案的例子。
var blob = new Blob(['Hello World']); var a = document.createElement('a'); a.href = window.URL.createObjectURL(blob); a.donwload = 'hello-world.txt'; a.textContent = 'Download Hello World'; body.appendChild(a);
上面的程式碼生成了一個超級連結,點選後提示下載文字檔案hello-world.txt,檔案內容為"Hello World"。
(2) Blob物件的slice方法,將二進位制資料按照位元組分塊,返回一個新的Blob物件。
var newBlob = oldBlob.slice(startingByte, endindByte);
下面是一個使用XMLHttpRequest物件,將大檔案分割上傳的例子。
function upload(blobOrFile) { var xhr = new XMLHttpRequest(); xhr.open('POST', '/server', true); xhr.onload = function(e) { ... }; xhr.send(blobOrFile); } document.querySelector('input[type="file"]').addEventListener('change', function(e) { var blob = this.files[0]; var BYTES_PER_CHUNK = 1024 * 1024; // 1MB chunk sizes. var SIZE = blob.size; var start = 0; var end = BYTES_PER_CHUNK; while(start < SIZE) { upload(blob.slice(start, end)); start = end; end = start + BYTES_PER_CHUNK; } }, false);
(3)Blob物件有兩個只讀屬性:
- size:二進位制資料的大小,單位為位元組。
- type:二進位制資料的MIME型別,全部為小寫,如果型別未知,則該值為空字串。
在Ajax操作中,如果xhr.responseType設為blob,接收的就是二進位制資料。
2、FileList物件
FileList物件針對表單的File控制元件。當用戶通過file控制元件選取檔案後,這個控制元件的files屬性值就是FileList物件。它在結構上類似於陣列,包含使用者選取的多個檔案。
<input type="file" id="input" onchange="console.log(this.files.length)" multiple />
當用戶選取檔案後,就可以讀取該檔案。
var selected_file = document.getElementById('input').files[0];
採用拖放方式,也可以得到FileList物件。
var dropZone = document.getElementById('drop_zone'); dropZone.addEventListener('drop', handleFileSelect, false); function handleFileSelect(evt) { evt.stopPropagation(); evt.preventDefault(); var files = evt.dataTransfer.files; // FileList object. // ... }
上面程式碼的 handleFileSelect 是拖放事件的回撥函式,它的引數evt是一個事件物件,該引數的dataTransfer.files屬性就是一個FileList物件,裡面包含了拖放的檔案。
3、File物件
File物件是FileList物件的成員,包含了檔案的一些元資訊,比如檔名、上次改動時間、檔案大小和檔案型別。它的屬性值如下:
- name:檔名,該屬性只讀
- size:檔案大小,單位為位元組,該屬性只讀
- type:檔案的MIME型別,如果分辨不出型別,則為空字串,該屬性只讀。
- lastModifiedDate:檔案的上次修改時間,該屬性只讀。
var selected_file = document.getElementById('input').files[0]; var fileName = selected_file.name; var fileSize = selected_file.size; var fileType = selected_file.type;
4、FileReader 物件
FileReader物件接收File物件或Blob物件作為引數,用於讀取檔案的實際內容,即把檔案內容讀入記憶體。對於不同型別的檔案,FileReader使用不同的方法讀取。
- FileReader.readAsBinaryString(Blob|File) :讀取結果為二進位制字串,每個位元組包含一個0到255之間的整數。
- FileReader.readAsText(Blob|File, opt_encoding) :讀取結果是一個文字字串。預設情況下,文字編碼格式是'UTF-8',可以通過可選的格式引數,指定其他編碼格式的文字。
- FileReader.readAsDataURL(Blob|File) : 讀取結果是一個基於Base64編碼的 data-uri 物件。
- FileReader.readAsArrayBuffer(Blob|File) :讀取結果是一個 ArrayBuffer 物件。
FileReader採用非同步方式讀取檔案,可以為一系列事件指定回撥函式。
- onabort:讀取中斷或呼叫reader.abort()方法時觸發。
- onerror:讀取出錯時觸發。
- onload:讀取成功後觸發。
- onloadend:讀取完成後觸發,不管是否成功。觸發順序排在 onload 或 onerror 後面。
- onloadstart:讀取將要開始時觸發。
- onprogress:讀取過程中週期性觸發。
下面的程式碼是如何展示文字檔案的內容。
var reader = new FileReader(); reader.onload = function(e){ console.log(e.target.result); } reader.readAsText(blob);
onload事件的回撥函式接受一個事件物件,該物件的target.result就是檔案的內容。
下面是一個使用readAsDataURL方法,為img元素新增src屬性的例子。
var reader = new FileReader(); reader.onload = function(e) { document.createElement('img').src = e.target.result; }; reader.readAsDataURL(f);
下面是一個onerror事件回撥函式的例子。
var reader = new FileReader(); reader.onerror = errorHandler; function errorHandler(evt) { switch(evt.target.error.code) { case evt.target.error.NOT_FOUND_ERR: alert('File Not Found!'); break; case evt.target.error.NOT_READABLE_ERR: alert('File is not readable'); break; case evt.target.error.ABORT_ERR: break; default: alert('An error occurred reading this file.'); }; }
下面是一個onprogress事件回撥函式的例子,主要用來顯示讀取進度。
var reader = new FileReader(); reader.onprogress = updateProgress; function updateProgress(evt) { if (evt.lengthComputable) { var percentLoaded = Math.round((evt.loaded / evt.totalEric Bidelman) * 100); var progress = document.querySelector('.percent'); if (percentLoaded < 100) { progress.style.width = percentLoaded + '%'; progress.textContent = percentLoaded + '%'; } } }
讀取大檔案的時候,可以利用Blob物件的slice方法,將大檔案分成小段,逐一讀取,這樣可以加快處理速度。
5、URL物件
URL物件用於生成指向File物件或Blob物件的URL。
var objecturl = window.URL.createObjectURL(blob);
上面的程式碼會對二進位制資料生成一個URL,類似於“blob:http%3A//test.com/666e6730-f45c-47c1-8012-ccc706f17191”。這個URL可以放置於任何通常可以放置URL的地方,比如img標籤的src屬性。需要注意的是,即使是同樣的二進位制資料,每呼叫一次URL.createObjectURL方法,就會得到一個不一樣的URL。
這個URL的存在時間,等同於網頁的存在時間,一旦網頁重新整理或解除安裝,這個URL就失效。除此之外,也可以手動呼叫URL.revokeObjectURL方法,使URL失效。
window.URL.revokeObjectURL(objectURL);
下面是一個利用URL物件,在網頁插入圖片的例子。
var img = document.createElement("img"); img.src = window.URL.createObjectURL(files[0]); img.height = 60; img.onload = function(e) { window.URL.revokeObjectURL(this.src); } body.appendChild(img); var info = document.createElement("span"); info.innerHTML = files[i].name + ": " + files[i].size + " bytes"; body.appendChild(info);
還有一個本機視訊預覽的例子。
var video = document.getElementById('video'); var obj_url = window.URL.createObjectURL(blob); video.src = obj_url; video.play() window.URL.revokeObjectURL(obj_url);
6、參考連結
https://www.cnblogs.com/jscode/archive/2013/04/27/3572239.html