這裏將繼續介紹一下FileReader,用FileReader具體地讀取文件內容。javascript
NOTE: 在chrome瀏覽器上本地測試的時候,即以file://xxx這種形式測試本文中的demo,會出現FileReader讀取不到內容的狀況,表現爲 FileReader的result爲空或者FileReader根本就沒有去讀取文件內容,FileReader各個事件沒有觸發;這種狀況我想應該是 相似於chrome不容許添加本地cookie那樣,chrome也不容許以file://xxx這種頁面上的js代碼訪問文件內容;解決辦法很簡單,只 須要將測試文件放到一個web服務器上,以http://xxx形式訪問便可。
前文主要介紹獲取文件句柄的方法,接下來咱們就要利用該文件句柄來讀取文件內容,這是經過FileReader來實現的,經過FileReader接口,咱們能夠異步地將文件內容加載到內存中,賦予某個js變量。php
FileReader具體支持哪些方法和事件,這裏就不介紹了,有興趣的能夠去w3c官網上看看FileReader介紹,這裏主要介紹一下FileReader兩個常見應用。css
一、預覽本地圖片
這裏主要用到FileReader的readAsDataURL方法,經過將圖片數據讀取成Data URL的方法,將圖片展現出來,關於DATA URI。html
示例腳本:html5
- function fileSelect(e) {
- e = e || window.event;
-
- var files = e.target.files;
- var ireg = /image\/.*/i,
- p = document.getElementById('Preview');
-
- var ul = document.getElementById('Errors');
- for(var i = 0, f; f = files[i]; i++) {
- if(!f.type.match(ireg)) {
-
- var li = document.createElement('li');
- li.innerHTML = '<li>' + f.name +'不是圖片文件.</li>';
-
- ul.appendChild(li);
-
- continue;
- }
-
- var reader = new FileReader();
-
- reader.onload = (function(file) {
- return function(e) {
- var span = document.createElement('span');
- span.innerHTML = '<img class="thumb" src="'+ this.result +'" alt="'+ file.name +'" />';
-
- p.insertBefore(span, null);
- };
- })(f);
-
- reader.readAsDataURL(f);
- }
- }
-
- if(window.File && window.FileList && window.FileReader && window.Blob) {
- document.getElementById('Files').addEventListener('change', fileSelect, false);
- } else {
- document.write('您的瀏覽器不支持File Api');
- }
由以上代碼可知,調用FileReader的readAsDataURL接口,將啓動異步加載文件內容,經過給reader監聽一個onload事件,將數據加載完畢後,在onload事件處理中,經過reader的result屬性便可得到文件內容。java
點擊此處查看demo>>web
NOTE:在示例中,我給圖片指定了一個height:75px的css樣式,主要是爲了讓瀏覽器對圖片進行等比縮放處理,因此在瀏覽器中展現出來的圖片 並非原始大小的圖片,而是通過瀏覽器自動等比縮放的圖片;若是須要查看原始尺寸圖片,可點擊相應圖片;再次單擊該圖片,則恢復小圖片。chrome
二、預覽文本文件
這裏主要用到FileReader的readAsText,對於諸如mimetype爲text/plain、text/html等文件均認爲是文本文件,即minetype爲text開頭都能在本例中預覽。api
NOTE:因爲須要在頁面上預覽文本,若是使用innerHTML插入文本的話,則須要對html中一些特殊字符進行實體編碼,這樣才能保證正常顯示文本。瀏覽器
簡易的encodeHTML方法:
- function encodeHTML(source) {
- return source
- .replace(/&/g, '&')
- .replace(/</g, '<')
- .replace(/>/g, '>')
- .replace(/"/, '"')
- .replace(/'/, ''');
- };
- function fileSelect(e) {
- e = e || window.event;
-
- var files = e.target.files;
- var ireg = /text\/.*/i,
- p = document.getElementById('Preview');
-
- var ul = document.getElementById('Errors');
- for(var i = 0, f; f = files[i]; i++) {
- console.log(f.type);
- if(!f.type.match(ireg)) {
-
- var li = document.createElement('li');
- li.innerHTML = '<li>' + f.name +'不是文本文件.</li>';
-
- ul.appendChild(li);
-
- continue;
- }
-
- var reader = new FileReader();
-
- reader.onload = (function(file) {
- return function(e) {
- var div = document.createElement('div');
- div.className = "text"
- div.innerHTML = encodeHTML(this.result);
-
- p.insertBefore(div, null);
- };
- })(f);
-
- reader.readAsText(f);
- }
- }
-
- if(window.File && window.FileList && window.FileReader && window.Blob) {
- document.getElementById('Files').addEventListener('change', fileSelect, false);
- } else {
- document.write('您的瀏覽器不支持File Api');
- }
點擊此處查看demo>>
2、分段讀取文件內容(slice)
有的時候,一次性將一個大文件讀入內存,並非一個很好的選擇(若是文件太大,使用FileReader讀取文件內容,可能直接致使瀏覽器崩潰),w3c也想到了這種狀況,因此html5容許對文件進行分段讀取。
chrome以及firefox已經將File slice api調整爲以下:
- var blob;
-
- if(file.webkitSlice) {
- blob = file.webkitSlice(start, end + 1, 'text/plain;charset=UTF-8');
- } else if(file.mozSlice) {
- blob = file.mozSlice(start, end + 1, 'text/plain;charset=UTF-8');
- }
本例使用了FileReader的onloadend事件來檢測讀取成功與否,若是用onloadend則必須檢測一下FileReader readyState,由於read abort時也會觸發onloadend事件,若是咱們採用onload,則能夠不用檢測readyState。
示例代碼:
- function readBlob(start, end) {
- var files = document.getElementById('file').files;
-
- if(!files.length) {
- alert('請選擇文件');
- return false;
- }
-
- var file = files[0],
- start = parseInt(start, 10) || 0,
- end = parseInt(end, 10) || (file.size - 1);
-
- var r = document.getElementById('range'),
- c = document.getElementById('content');
-
- var reader = new FileReader();
-
- reader.onloadend = function(e) {
- if(this.readyState == FileReader.DONE) {
- c.textContent = this.result;
- r.textContent = "Read bytes: " + (start + 1) + " - " + (end + 1) + " of " + file.size + " bytes";
- }
- };
- var blob;
-
- if(file.webkitSlice) {
- blob = file.webkitSlice(start, end + 1, 'text/plain;charset=UTF-8');
- } else if(file.mozSlice) {
- blob = file.mozSlice(start, end + 1, 'text/plain;charset=UTF-8');
- }
-
- reader.readAsBinaryString(blob);
- };
-
- try {
- document.getElementById('buttons').addEventListener('click', function(e) {
- if(e.target.tagName.toLowerCase() == 'button') {
- var start = e.target.getAttribute('data-start'),
- end = e.target.getAttribute('data-end');
-
- readBlob(start, end);
- }
- });
- } catch(ex) {
- alert('something error happens!')
- }
點擊此處查看demo>>
NOTE:readAsBinaryString這個方法,讀取的二進制字符串,在頁面顯示,出現中文亂碼,不知道怎麼解決,若是用reader.readAsText便可正常顯示中文;在w3c官網上:binary string, in which every byte is represented by an integer in the range [0..255],而中文卻不在[0...255]內,難道是由於這樣纔出現亂碼?
3、FileReader進度條
既然FileReader是異步讀取文件內容,那麼就應該能夠監聽它的讀取進度。事實上,FileReader的onloadstart以及onprogress等事件,能夠用來監聽FileReader的讀取進度。
在onprogress的事件處理器中,提供了一個ProgressEvent對象,這個事件對象實際上繼承了Event對象,提供了三個只讀屬 性:lengthComputable、loaded、total;經過以上幾個屬性,便可實時顯示讀取進度。w3c官網上對它的定義以下:
- interface ProgressEvent : Event {
- readonly attribute boolean lengthComputable;
- readonly attribute unsigned long long loaded;
- readonly attribute unsigned long long total;
- };
若是處理的文件太大,可能會致使瀏覽器崩潰(chrome下通常都會崩潰掉,而firefox則不會,不過會觸發FileReader的onerror事 件,文件讀取失敗),因此爲了安全地、正常地觀察到文件讀取進度,咱們採用分段讀取的方法來測試FileReader的進度條。
HTML代碼以下:
- <form>
- <fieldset>
- <legend>分度讀取文件:</legend>
- <input type="file" id="File" />
- <input type="button" value="中斷" id="Abort" />
- <p>
- <label>讀取進度:</label><progress id="Progress" value="0" max="100"></progress>
- </p>
- <p id="Status"></p>
- </fieldset>
- </form>
JS代碼以下:
- var h = {
- init: function() {
- var me = this;
-
- document.getElementById('File').onchange = me.fileHandler;
- document.getElementById('Abort').onclick = me.abortHandler;
-
- me.status = document.getElementById('Status');
- me.progress = document.getElementById('Progress');
- me.percent = document.getElementById('Percent');
-
- me.loaded = 0;
-
- me.step = 1024 * 1024;
- me.times = 0;
- },
- fileHandler: function(e) {
- var me = h;
-
- var file = me.file = this.files[0];
-
- var reader = me.reader = new FileReader();
-
-
- me.total = file.size;
-
- reader.onloadstart = me.onLoadStart;
- reader.onprogress = me.onProgress;
- reader.onabort = me.onAbort;
- reader.onerror = me.onerror;
- reader.onload = me.onLoad;
- reader.onloadend = me.onLoadEnd;
-
- me.readBlob(file, 0);
- },
- onLoadStart: function() {
- var me = h;
- },
- onProgress: function(e) {
- var me = h;
-
- me.loaded += e.loaded;
-
- me.progress.value = (me.loaded / me.total) * 100;
- },
- onAbort: function() {
- var me = h;
- },
- onError: function() {
- var me = h;
-
- },
- onLoad: function() {
- var me = h;
-
- if(me.loaded < me.total) {
- me.readBlob(me.loaded);
- } else {
- me.loaded = me.total;
- }
- },
- onLoadEnd: function() {
- var me = h;
-
- },
- readBlob: function(start) {
- var me = h;
-
- var blob,
- file = me.file;
-
- me.times += 1;
-
- if(file.webkitSlice) {
- blob = file.webkitSlice(start, start + me.step + 1);
- } else if(file.mozSlice) {
- blob = file.mozSlice(start, start + me.step + 1);
- }
-
- me.reader.readAsText(blob);
- },
- abortHandler: function() {
- var me = h;
-
- if(me.reader) {
- me.reader.abort();
- }
- }
- };
-
- h.init();
例子中的進度條採用html5 progress元素來實現的。
每次讀取1M的字節(你也能夠隨便改步長,好比說一次一個字節,而後傳一個大小爲幾字節的文件,也能很好地觀察到進度),在一次讀取完畢後,onload事件中開啓下一次讀取,直至整個文件都讀取完畢。
若是您的瀏覽器支持html5,您能夠試一下:
這個示例中,沒有限制文件大小,讀取大文件時,也不會出現瀏覽器崩潰的狀況,能夠正常觀察到文件的讀取進度。