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、參考鏈接

[1] W3C Working Draft

[2] Andrew Dodson, Get Loaded with the File API

[3] Mozilla Developer Network, Using files from web applications

[4] HTML5 download attribute

[5] Eric Bidelman, Reading files in JavaScript using the File APIS

 

注:本文轉自http://javascript.ruanyifeng.com/htmlapi/file.html,有修改。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM