簡(jiǎn)介
在HTML5中竟趾,文件選擇標(biāo)簽file增加了如下兩個(gè)屬性:
- multiple:設(shè)定當(dāng)前元素可以選取多個(gè)文件略水。
- accept:設(shè)定當(dāng)前選擇器可以選擇的MIME類型或后綴名猖辫。
<input type="file" multiple name="" id="myfilePhoto" value="" accept="image/jpg, image/png">
于此同時(shí)饵婆,其出現(xiàn)了FileReader對(duì)象伞鲫,使用FileReader對(duì)象,web應(yīng)用程序可以異步的讀取存儲(chǔ)在用戶計(jì)算機(jī)上的文件(或者原始數(shù)據(jù)緩沖)內(nèi)容,可以使用File對(duì)象或者Blob對(duì)象來指定所要處理的文件或數(shù)據(jù)。
FileReader:是window對(duì)象的一個(gè)構(gòu)造函數(shù),用于讀取文件選擇標(biāo)簽選擇的File的Dom對(duì)象抛姑。即用來把文件選擇的信息讀入內(nèi)存赞厕,并且讀取文件中的數(shù)據(jù)。其接口提供了一個(gè)異步API定硝,使用該API可以在瀏覽器主線程中異步訪問文件系統(tǒng)皿桑,讀取文件中的數(shù)據(jù)。為了安全FileReader可以讀取表單上已經(jīng)選擇的文件蔬啡,不能讀取本地文件诲侮,它以二進(jìn)制信息的方式讀取表單文件:主要用于大文件的信息讀取。
特點(diǎn):
- 讀取后箱蟆,二進(jìn)制信息在瀏覽器內(nèi)存中沟绪,批量的向服務(wù)器進(jìn)行傳輸。
- 一般要配合后臺(tái)程序空猜,第三方插件共同完成
- 斷點(diǎn)下載和斷點(diǎn)上傳
使用介紹
創(chuàng)建FileReader對(duì)象
想要?jiǎng)?chuàng)建一個(gè)FileReader對(duì)象,很簡(jiǎn)單,如下:
var fr = new FileReader();
FileReader的狀態(tài)常量:
|常量名 | 值 | 描述
|-
|EMPTY | 0 | 還沒有加載任何數(shù)據(jù).
|LOADING | 1 | 數(shù)據(jù)正在被加載.
|DONE | 2 | 已完成全部的讀取請(qǐng)求.
FileReader接口的方法
FileReader接口有5個(gè)方法绽慈,其中4個(gè)用來讀取文件恨旱,另一個(gè)用來中斷讀取。無論讀取成功或失敗坝疼,方法并不會(huì)直接返回讀取結(jié)果搜贤,這一結(jié)果存儲(chǔ)在result屬性中。
FileReader接口的方法:
|方法名 | 參數(shù) | 描述
|-
|readAsArrayBuffer | file | 將文件讀取為一個(gè)ArrayBuffer對(duì)象以表示所讀取文件的內(nèi)容.
|readAsBinaryString | file | 將文件讀取為二進(jìn)制編碼
|readAsText | file,[encoding] | 將文件讀取為文本
|readAsDataURL | file | 將文件讀取為DataURL钝凶,讀取的內(nèi)容是加密以后的本地文件路徑
|abort | (none) | 終端讀取操作
FileReader的屬性:
|屬性名 | 類型 | 描述
|-
|error | DOMError | 在讀取文件時(shí)發(fā)生的錯(cuò)誤. 只讀.
|readyState | unsigned short | 表明FileReader對(duì)象的當(dāng)前狀態(tài). 值為State constants中的一個(gè). 只讀
|result | jsval | 讀取到的文件內(nèi)容.這個(gè)屬性只在讀取操作完成之后才有效,并且數(shù)據(jù)的格式取決于讀取操作是由哪個(gè)方法發(fā)起的. 只讀.
FileReader接口事件
FileReader接口包含了一套完整的事件模型仪芒,用于捕獲讀取文件時(shí)的狀態(tài)。
FileReader接口的事件:
|事件 | 描述
|-
|onabort | 中斷
|onerror | 出錯(cuò)
|onloadstart | 開始
|onprogress | 正在讀取
|onload | 成功讀取
|onloadend | 讀取完成耕陷,無論成功失敗
實(shí)例說明一切:
講完這些大家其實(shí)還是不知道怎么用掂名,于是,實(shí)例來說明一切:
<!-- multiple多個(gè)文件 -->
<input type="file" multiple name="" id="myfilePhoto" value="" accept="image/jpg, image/png">
<ul class="fileUl"></ul>
<script>
document.getElementById('myfilePhoto').addEventListener("change",function(){
var inputFile = document.getElementById('myfilePhoto');
for(var i = 0; i<inputFile.files.length ;i++){
var fr = new FileReader(); // 這個(gè)FileReader應(yīng)該對(duì)應(yīng)于每一個(gè)讀取的文件都需要重新new一個(gè)
var files = inputFile.files[i]; // files可以獲取當(dāng)前文件輸入框中選擇的所有文件哟沫,返回列表
fr.readAsDataURL(files); // 讀取的內(nèi)容是加密以后的本地文件路徑
fr.onload = function(e){ // 數(shù)據(jù)讀取完成時(shí)觸發(fā)onload對(duì)應(yīng)的響應(yīng)函數(shù)
// e.target是FileReader等同于fr
var ulLi = document.createElement('li');
var ulLiA = document.createElement('a');
var ulLiimg = document.createElement('img');
ulLiimg.src = e.target.result
ulLiA.appendChild(ulLiimg);
ulLi.appendChild(ulLiA);
console.log(document.getElementsByClassName('fileUl'))
document.getElementsByClassName('fileUl')[0].appendChild(ulLi)
}
}
});
</script>
<script>
function updateSize() {
var nBytes = 0;
var oFiles = document.getElementById("uploadInput").files;
var nFiles = oFiles.length;
for (var nFileId = 0; nFileId < nFiles; nFileId++) {
nBytes += oFiles[nFileId].size;
}
var sOutput = nBytes + " bytes";
var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"];
var nMultiple = 0, nApprox = nBytes / 1024;
for ( ; nApprox > 1; nApprox /= 1024, nMultiple++) {
sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)";
}
document.getElementById("fileNum").innerHTML = nFiles;
document.getElementById("fileSize").innerHTML = sOutput;
}
</script>
<p>
<input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple>
選擇的文件數(shù):<span id="fileNum">0</span>
總共大薪让铩:<span id="fileSize">0</span>
</p>
注意:在遍歷時(shí)把 var fileReader = new FileReader(); 放到了循環(huán)之外,會(huì)導(dǎo)致了 Uncaught InvalidStateError: Failed to execute 'readAsDataURL' on 'FileReader': The object is already busy reading Blobs.錯(cuò)誤,這個(gè)FileReader應(yīng)該對(duì)應(yīng)于每一個(gè)讀取的文件都需要重新new一個(gè)南用。
onload只在所有數(shù)據(jù)讀取成功完成時(shí)觸發(fā)膀钠,并且結(jié)果也只在onload之后才有。
問題解釋:因?yàn)槟忝看窝h(huán)如果只new了一次相當(dāng)與你只創(chuàng)建一個(gè)fileReader對(duì)象裹虫,可是我們每次循環(huán)時(shí)肿嘲,拿到的文件信息卻是不同的,這就好比你雇了一個(gè)員工筑公,要求他同時(shí)去打掃衛(wèi)生間又打掃辦公室又去澆花雳窟,他只能先干完一件才能去干另一件,所以它就會(huì)給你報(bào)錯(cuò):The object is already busy reading Blobs.對(duì)象已經(jīng)在忙著閱讀Blobs-即忙著處理不可變的類似文件對(duì)象的原始數(shù)據(jù)匣屡。你一定會(huì)疑問我是for循環(huán)一次完成了胺饩取?你別忘了fr.onload是一個(gè)異步的捣作,你for一次完成誉结,但是處理信息并沒有完成,這就是你指揮員工命令已完成券躁,但是惩坑,員工干活卻還在干,因?yàn)楦苫钜彩且獣r(shí)間的也拜。
FileReader接口的使用
實(shí)例結(jié)束再來個(gè)大點(diǎn)案例:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
var result=document.getElementById("result");
var file=document.getElementById("file");
//判斷瀏覽器是否支持FileReader接口
if(typeof FileReader == 'undefined'){
result.InnerHTML="<p>你的瀏覽器不支持FileReader接口以舒!</p>";
//使選擇控件不可操作
file.setAttribute("disabled","disabled");
}
function readAsDataURL(){
//檢驗(yàn)是否為圖像文件
var file = document.getElementById("file").files[0];
if(!/image\/\w+/.test(file.type)){
alert("看清楚,這個(gè)需要圖片慢哈!");
return false;
}
var reader = new FileReader();
//將文件以Data URL形式讀入頁面
reader.readAsDataURL(file);
reader.onload=function(e){
var result=document.getElementById("result");
//顯示文件
result.innerHTML='![](' + this.result +')';
}
}
function readAsBinaryString(){
var file = document.getElementById("file").files[0];
var reader = new FileReader();
//將文件以二進(jìn)制形式讀入頁面
reader.readAsBinaryString(file);
reader.onload=function(f){
var result=document.getElementById("result");
//顯示文件
result.innerHTML=this.result;
}
}
function readAsText(){
var file = document.getElementById("file").files[0];
var reader = new FileReader();
//將文件以文本形式讀入頁面
reader.readAsText(file);
reader.onload=function(f){
var result=document.getElementById("result");
//顯示文件
result.innerHTML=this.result;
}
}
</script>
<p>
<label>請(qǐng)選擇一個(gè)文件:</label>
<input type="file" id="file" />
<input type="button" value="讀取圖像" onclick="readAsDataURL()" />
<input type="button" value="讀取二進(jìn)制數(shù)據(jù)" onclick="readAsBinaryString()" />
<input type="button" value="讀取文本文件" onclick="readAsText()" />
</p>
<div id="result" name="result"></div>
</body>
</html>