HTML5中的文件讀取---File API

1.簡介

在Html5中提供了一種通過File API規(guī)范與本地文件進(jìn)行交互的標(biāo)準(zhǔn)方法。在使用 File API 在向服務(wù)器發(fā)送圖片的過程中可以創(chuàng)建圖片的縮略圖預(yù)覽,也可以允許應(yīng)用程序在用戶離線時(shí)保存文件引用。另外弦牡,您可以使用客戶端邏輯來驗(yàn)證上傳內(nèi)容的 type 與其文件擴(kuò)展名是否匹配灭将,或者限制上傳內(nèi)容的大小泄伪。
該規(guī)范通過“本地”文件系統(tǒng)提供了多種文件訪問接口:

1.1 FileList 對象

filelist對象是針對表單的file控件挫望,當(dāng)用戶利用file控件選取文件以后立润,這個(gè)控件的files屬性就是filelist對象。

//使用多選控件
<input type='file' id="file-test" multiple />
<script>
    document.getElementById('file-test').onchange = function() {
      console.log(this.files);
    };
</script>
image.png

注:除了file控件以外媳板,采用拖放的方式桑腮,也可以得到filelist對象。一般情況下蛉幸,filelist對象只能被動(dòng)的讀取破讨,不可以手動(dòng)構(gòu)造,只有在user主動(dòng)觸發(fā)(選取或拖拽)了文件讀取的行為奕纫,javascript才會(huì)訪問到filelist提陶。

1.2 File對象

在filelist對象中就包括了file對象,file對象含有以下的屬性:

name: 文件名匹层,只讀屬性隙笆;
size: 文件大小,單位為字節(jié)升筏,只讀屬性撑柔;
type: 文件的MIME類型,若是分辨不出類型您访,則為空字符串铅忿,只讀屬性;
lastModified:文件的上次修改時(shí)間灵汪,格式為時(shí)間戳檀训;
lastModifiedDate:文件上次修改時(shí)間,格式為Date對象實(shí)例识虚。

如下圖所示:


image.png

1.3 Blob對象

Blob(Binary Large Object)對象代表了一段二進(jìn)制數(shù)據(jù)肢扯,提供了一系列操作接口,其他二進(jìn)制數(shù)據(jù)的API(比如File對象)担锤,都是建立在Blob對象基礎(chǔ)上的蔚晨,繼承了它的屬性和方法。
生成Blob對象有兩種方法:一種是使用Blob構(gòu)造函數(shù)肛循,另一中是對現(xiàn)有的Blob對象使用slice方法切出一部分铭腕。

1.4 FileReader

FileReader對象用于讀取文件,他的參數(shù)是file對象或blob對象多糠。對于不同類型的文件累舷,F(xiàn)ileReader提供了不同的讀取方法:

  • readerAsText(blob|File,opt_encoding) :
    返回文本字符串,默認(rèn)情況下夹孔,文本編碼格式是UTF-8被盈,可以通過可選參數(shù)指定其他編碼格式的文本析孽。
  • readerAsDataURL(Blob|File) :
    返回一個(gè)基于Base64編碼的data-uri對象(可用于<img>標(biāo)簽中的src屬性,從而達(dá)到圖片預(yù)覽的效果)只怎。
  • readerAsArrayBuffer(Blob|File) :
    返回一個(gè)ArrayBuffer對象袜瞬。

FileReader對象采用異步方式讀取文件,可以為一系列的事件指定回調(diào)函數(shù)身堡。

  • onabort() 方法 :讀取中段或者調(diào)用reader.abort()方法時(shí)觸發(fā)邓尤。
  • onerror() 方法 :讀取出錯(cuò)時(shí)觸發(fā)。
  • onload() 方法 :讀取成功后觸發(fā)贴谎。
  • onloadend() 方法 :讀取完成后觸發(fā)汞扎,不管是否成功。觸發(fā)順序排在onload或onerror后面擅这。
  • onloadstart() 方法 :讀取將要開始時(shí)觸發(fā)澈魄。
  • onprogress() 方法 :讀取過程中周期性觸發(fā)(一般可用于獲取文件的讀取進(jìn)度)。

1.5 createObjectURL 方法

調(diào)用URL對象的createObjectURL方法蕾哟,傳入一個(gè)File對象或者Blob對象一忱,能生成一個(gè)鏈接。這個(gè)URL可以放置于任何通程啡罚可以放置URL的地方帘营,比如<img>標(biāo)簽的src屬性。需注意的是即使是同樣的二進(jìn)制數(shù)據(jù)逐哈,每調(diào)用一次URL.createObjectURL方法芬迄。就會(huì)得到一個(gè)不一樣的URL。

var URL = window.URL || window.webkitURL || window.mozURL ;
var SRC = URL.createObjectURL(file);

1.6 onprogress 事件

想要上傳圖片的時(shí)候顯示進(jìn)度條昂秃,在HTML5中提供了onprogress事件禀梳。onprogress事件可以作用于<video>或<audio>標(biāo)簽中,作為其狀態(tài)回調(diào)函數(shù)的作用肠骆。也可以作為XMLHttpRequest的指定事件算途,XMLHttpRequest對象在傳遞數(shù)據(jù)的時(shí)候,提供了一個(gè)progress事件蚀腿,用于返回進(jìn)度信息嘴瓤。它分為 上傳 和 下載 兩種情況:

  • 下載的 progress 事件屬于 XMLHttpRequest 對象
  • 上傳的 progress 事件屬于 XMLHttpRequest.upload 對象

當(dāng)上傳或者下載時(shí),會(huì)頻繁調(diào)用該方法莉钙。該方法接受一個(gè)事件參數(shù)event,其中event.total是需要傳輸?shù)目傋止?jié)廓脆,event.loaded是已經(jīng)傳輸?shù)淖止?jié)。如果event.lengthComputable 不為真磁玉,則event.total等于0停忿。
示例代碼:

<body>
    <input type="file" id="file">
    <div class="progress">
        <div></div>
    </div>
    <button onclick="ajaxUpload()">上傳</button>
    <script>
        function ajaxUpload() {
            var file = $('#file').get(0).files[0];
            var formdata = new FormData();
            formdata.append('file', file);
            $.ajax({
                url: 'test_progress.php',
                type: 'post',
                dataType: 'json',
                data: formdata,//這里上傳的數(shù)據(jù)使用了formData 對象
                processData: false,  //必須false才會(huì)自動(dòng)加上正確的Content-Type 
                contentType: false,  //必須設(shè)置
               //這里我們先拿到j(luò)Query產(chǎn)生的 XMLHttpRequest對象,為其增加 progress 事件綁定蚊伞,然后再返回交給ajax使用.
                xhr: () => {
                    var xhr = new XMLHttpRequest();
                    xhr.upload.onprogress = (evt) => {
                        console.log(evt);
                        var progressWidth = (evt.loaded / evt.total) * 100 + '%';
                        $('.progress > div').css('width', progressWidth);
                    }
                    return xhr;
                }
            })
        }
    </script>
</body>

2.檢查環(huán)境

在編寫前請先檢查您當(dāng)前的瀏覽器是否支持File API:

if(window.File &&window.FileReader &&window.FileList &&window.Blob) {
    alert( "Success! The File APIs are fully supported in this browser")
}else{ 
     alert('The File APIs are not fully supported in this browser.'); 
 }

3.選取文件

3.1 通過表單輸入進(jìn)行選取文件

選取文件最常用的方法就死使用標(biāo)準(zhǔn)的<input type="file">元素席赂,JS會(huì)返回選定的File對象的列表吮铭,下面的示例是使用“multiple”屬性實(shí)現(xiàn)同時(shí)選定多個(gè)文件:

  <div style="margin:0 auto;width:400px;height:200px;border:2px dashed pink">
    <input type="file" id="filetest" name="filetest" multiple />
    <output id="filelist"></output>  
  </div> 
  <script>
    function handleFileSelect(event){
      var files = event.target.files;
      var output = [];
      var i,f;
      for(i=0;f=files[i];i++){
        output.push('<li><strong>',f.name,'</strong>','-',f.size, 'bytes,last modified:',f.lastModifiedDate,'</li>');
      }
      document.getElementById("filelist").innerHTML = '<ul>'+output.join('')+'</ul>';
      
    }
    document.getElementById("filetest").addEventListener('change',handleFileSelect,false);
  </script>
image.png

3.2 通過拖拽選取文件并顯示縮略圖

該方法是在本地將文件從桌面拖放到瀏覽器進(jìn)行選取,并顯示圖片的縮略圖氧枣,具體示例如下:

<style>
   .thumb {
      height: 80px;
      border: 1px solid #eee;
      margin: 10px 5px 0 0;
    }
</style>
<body>
  <div style="width: 320px;margin: 0 auto;border:2px solid skyblue;padding:10px;">
    <div id="drop_zone" style="border:2px dashed pink;color:#bbb;text-align: center;line-height:76px;">Drop files here</div>
    <output id="list"></output>
  </div>
  <script>
    $(document).ready(function() {
      function handleFileSelect(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        var files = evt.dataTransfer.files; // 拖拽選取時(shí)沐兵,F(xiàn)ileList 對象格式.
        var i,f;
        for (i = 0; f = files[i]; i++) {
          // 匹配圖片格式
          if (!f.type.match('image.*')) {
            continue;
          }
          var reader = new FileReader(); //讀取文件信息
          // 捕獲文件信息的閉包
          reader.onload = (function(theFile) {
            return function(e) {
              // 顯示縮略圖
              var span = document.createElement('span');
              span.innerHTML = ['<img class="thumb" src="', e.target.result,
                                '" title="', escape(theFile.name), '"/>'].join('');
              document.getElementById('list').insertBefore(span, null);
            };
          })(f);

          // 以URL的形式讀入圖像文件。
          reader.readAsDataURL(f);
        }
      }
      function handleDragOver(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        evt.dataTransfer.dropEffect = 'copy'; 
      }
      // 設(shè)置dnd時(shí)間偵聽器便监。
      var dropZone = document.getElementById('drop_zone');
      dropZone.addEventListener('dragover', handleDragOver, false);
      dropZone.addEventListener('drop', handleFileSelect, false);
  })
</script>

示例顯示結(jié)果如下:


image.png

3.2 監(jiān)聽上傳進(jìn)度

在HTML5中,提供了一個(gè)FormData對象碳想,能關(guān)于模擬一個(gè)原始的表單格式的數(shù)據(jù)烧董,在之前的表單數(shù)據(jù)傳輸中,必須要用form標(biāo)簽將要傳輸?shù)臄?shù)據(jù)包裹起來了胧奔,按照規(guī)定的格式與后臺傳輸逊移,HTML5中的FormData對象就模擬這種格式,將form表單元素的value值與對應(yīng)的name屬性結(jié)合起來龙填,組成一個(gè)querystring字符串胳泉。下面示例結(jié)合FormData實(shí)現(xiàn)通過onprogress事件監(jiān)控讀取狀態(tài),并以進(jìn)度條的形式顯示出來岩遗。
示例代碼如下:

      <div style="text-align: center; padding-top: 50px">
            <input type="file" id="avatarfile" accept="image/png, image/jpeg, image/jpg, video/*"/>
            <button onclick="to_upload_file()">上傳文件</button>
            <br>
            <div style="text-align: left;margin-top: 15px;display: inline-block;width: 300px; height: 20px; border: 1px solid #44A1F8; border-radius: 2px;position: relative">
                <div id="progress_bar" style="display: inline-block; width: 0px; height: 20px;background-color: #64B587"></div>
                <div style="text-align: center;width: 300px;position: absolute; top: 0; font-size:16px; color: #413F43">
                    <div id="loading-percent">
                        上傳進(jìn)度0%
                    </div>
                </div>  
            </div>
        </div>
        <script>
            function to_upload_file(){
                var fileObj = document.getElementById("avatarfile").files[0]
                if(fileObj){
                    var formContent = new FormData();
                    formContent.append("file", fileObj);
                    var xhr = new XMLHttpRequest();
                    xhr.upload.onprogress = (e)=>{
                      var progress_bar = document.getElementById("progress_bar");
                      var loadingPercent = document.getElementById("loading-percent");
                      if(e.lengthComputable){
                        var loading = Math.round(e.loaded / e.total * 100);
                      }
                      if(loading === 100){
                        loadingPercent.innerHTML = "上傳成功^_^";
                      }else{
                        loadingPercent.innerHTML = "上傳進(jìn)度"+loading+"%"
                      }  
                      progress_bar.style.width = String(loading * 3) + "px";
                    }; // 監(jiān)聽上傳進(jìn)度
                    xhr.upload.onload = (e)=>{console.log("Success !", e)}; // 上傳成功后的回調(diào)函數(shù)
                    xhr.upload.onerror =  (e)=>{console.log("Failed", e)}; // 上傳失敗后的回調(diào)函數(shù)
                    xhr.open("POST", "http://127.0.0.1/upload_test.php", true);
                    xhr.send(formContent);
                }else{
                    alert("當(dāng)前無上傳文件扇商,請先選擇文件后再上傳")
                }
            }
        </script>
參考文件:

http://www.reibang.com/p/b3e986fb1237
http://www.w3.org/TR/file-upload

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宿礁,隨后出現(xiàn)的幾起案子案铺,更是在濱河造成了極大的恐慌,老刑警劉巖梆靖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件控汉,死亡現(xiàn)場離奇詭異,居然都是意外死亡返吻,警方通過查閱死者的電腦和手機(jī)姑子,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來测僵,“玉大人街佑,你說我怎么就攤上這事『蘅危” “怎么了舆乔?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長剂公。 經(jīng)常有香客問我希俩,道長,這世上最難降的妖魔是什么纲辽? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任颜武,我火速辦了婚禮璃搜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鳞上。我一直安慰自己这吻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布篙议。 她就那樣靜靜地躺著唾糯,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鬼贱。 梳的紋絲不亂的頭發(fā)上移怯,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音这难,去河邊找鬼舟误。 笑死,一個(gè)胖子當(dāng)著我的面吹牛姻乓,可吹牛的內(nèi)容都是我干的嵌溢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蹋岩,長吁一口氣:“原來是場噩夢啊……” “哼赖草!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起星澳,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疚顷,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后禁偎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體腿堤,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年如暖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了笆檀。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盒至,死狀恐怖酗洒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情枷遂,我是刑警寧澤樱衷,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站酒唉,受9級特大地震影響矩桂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痪伦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一侄榴、第九天 我趴在偏房一處隱蔽的房頂上張望雹锣。 院中可真熱鬧,春花似錦癞蚕、人聲如沸蕊爵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽攒射。三九已至,卻和暖如春恒水,著一層夾襖步出監(jiān)牢的瞬間匆篓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工寇窑, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箩张。 一個(gè)月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓甩骏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親先慷。 傳聞我的和親對象是個(gè)殘疾皇子饮笛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容