基於HTML5的移動Web應用——檔案操作

新夢想IT發表於2023-03-28



過去Web程式不能替代桌面程式的一個重要原因就在於瀏覽器對於檔案操作API的缺失。照片處理中的裁剪、濾鏡,二維碼的讀取與識別,檔案的檢視和編輯等,這些操作無一不依賴檔案的操作,HTML5賦予了瀏覽器幾乎和本地程式同等強大的檔案操作能力。


File API是HTML5在DOM標準中新增的功能,它允許Web內容在使用者授權的情況下選擇本地檔案並讀取內容一透過 File,FileList 和FileReader等物件共同作用來實現。


選擇檔案


1、透過表單選擇檔案


由於Web環境的特殊性,為了考慮檔案安全問題,瀏覽器不允許JavaScript直接訪問檔案系統,但可以透過file型別的input元素或者拖放的方式選擇檔案操作。

<input type="file" id="thisFile"/>


File表單可以讓使用者選取一個或者多個檔案(multiple 屬性),透過FileAPI,可在使用者選擇檔案後訪問到代表了所選檔案列表的FileList物件,FileList 物件是一個類陣列的物件,其中包含著一個或多個File物件。如果沒有multiple屬性或者使用者只選了一個檔案,那麼只需要訪問FileList物件的第一個元素:

var filelist=document.getElementById('thisFile') .files;

var selectedFile-filelist[0]; 


使用input元素時,使用者在選擇檔案後會觸發其change事件:

var inputElement=document.getElementById('thisFile')

inputElement. addEventListener ("change",handleFiles, false)

function handleFiles(){

     var fileList=this.files 

}


和其他類陣列物件一樣,FileList 也有length屬性,可以輕鬆遍歷其File物件:

for (var i=0, numFiles=files.length ; i< numFiles; i++) {

    var file=files[i]

    ……

}


File物件有3個很有用的屬性,包括了關於該檔案的許多有用資訊。

(1) name: 檔名,不包含路徑資訊。

(2) size: 檔案大小,以B為單位。

(3) type:檔案的MIME type。

需要注意的是,這3個屬性都是隻讀的。


2、透過拖曳來選擇檔案


使用拖曳的方式來選擇檔案的效果,需要透過訪問dataTransfer的files屬性來實現。

下面透過一個案例來演示具體效果,如示例所示。

【示例】 使用拖曳的方式選擇檔案

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title></title>

</head>

<style>

    .dropzone{

        width: 200px;

        height: 100px;

        border: 2px  dashed #ddd;

        text-align: center;

        padding-top: 100px;

        color: #999;

    }

</style>

<body>

<div id="dropzone">

    拖曳檔案到此處

</div>

<div id="output">



</div>

<script>

    function getFileInfo(file) {

        var aMultiples = ["KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"], sizeinfo;

        var info = '檔名:' + file.name ;

        // 計算檔案大小的近似值

        for (var nMultiple = 0, nApprox = file.size / 1024; nApprox > 1; nApprox /= 1024, nMultiple++) {

            sizeinfo = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + file.size + " bytes)";

        }

        info += ";大小:" + sizeinfo

        info += ";型別:" + file.type



        return info + '<br>'

    }



    var dropzone = document.getElementById('dropzone');

    dropzone.addEventListener('drop', function (e) {

        var html = '您一共選擇了 ' + e.dataTransfer.files.length + '個檔案,檔案資訊如下:<br>';

        [].forEach.call(e.dataTransfer.files, function (file) {

            html += getFileInfo(file);

        });

        document.getElementById('output').innerHTML = html

        e.preventDefault();

        e.stopPropagation();

    }, false);

    dropzone.addEventListener('dragover', function (e) {

        if (e.preventDefault) {

            // 必須要阻止dragover的預設行為(即不可drop),這樣才能進行drop操作。

            // 否則不會觸發drop事件

            e.preventDefault();

        }

        return false

    }, false)

</script>

</body>

</html>


用Chrome瀏覽器訪問示例。


操作檔案


1、FileReader 物件


前面講到表單或者dataTansier物件中的File型別的例項代表著這個檔案,但是這個檔案物件只能訪問到一些基本的資訊(大小和檔名等),如果要訪問檔案的具體內容,還得藉助FileReader物件。


FileReader物件可以將檔案物件轉換為字串、DataURL物件或者二進位制字串等,以進行進一步操作。例如,在做圖片上傳功能時,可以先對選擇的圖片進行預覽或者剪裁,待使用者確認無誤後再進行上傳,可以節省許多不必要的頻寬。以前文的拖曳檔案例子為基礎,加上拖曳圖片預覽功能,程式碼如示例所示。


【示例】 FileReader物件

<!DOCTYPE html>

<html>

<head>

    <meta charset="UTF-8">

    <title></title>

</head>

<style>

    .dropzone {

        width: 200px;

        height: 100px;

        border: 2px dashed #ddd;

        text-align: center;

        padding-top: 100px;

        color: #999;

    }

    .preview img {

        width: 100px;

        height: 100px;

    }

</style>

<body>

<div id="dropzone">

    拖拽檔案到此處

</div>

<div id="preview">



</div>

<script>

    function handleFiles(files) {

        var preview = document.getElementById('preview')

        for (var i = 0; i < files.length; i++) {

            var file = files[i]

            // 用來過濾非圖片型別

            var imageType = /image.*/



            if (!file.type.match(imageType)) {

                continue

            }

            // 只能動態建立img物件來進行預覽

            var img = document.createElement("img")

            // 將檔案物件存起來

            img.file = file

            // 新建 FileRead 物件——是不是很簡單?

            var reader = new FileReader()

            // FileReader在讀取檔案時是非同步執行的(JS中許多物件都有類似API),因此需

            要透過繫結其load事件來訪問檔案讀取的結果

            // 要注意,這裡使用了閉包,因為img只儲存當前函式(handleFiles)內的引用,

            for迴圈並不會建立新的作用域

            // 因此要透過一個閉包的形式複製一份img的引用,否則img在for迴圈結束後將

            只引用最後一次建立的img元素。

            reader.{

                return function(e) {

                    // e.target.result 包含讀取到的 dataURL資訊

                    aImg.src = e.target.result

                    // 將圖片插入當前檔案

                    preview.appendChild(aImg)

                }

            })(img)

            reader.(e) {

                console.log('當前已載入:' + (e.loaded / e.total * 100).toFixed(2)

                        + '%')

            }

            // readAsDataURL方法將file物件讀取為dataURL

            reader.readAsDataURL(file)

        }

    }

    var dropzone = document.getElementById('dropzone')

    dropzone.addEventListener('drop', function (e) {

        handleFiles(e.dataTransfer.files)

        e.preventDefault()

        e.stopPropagation()

    }, false)

    dropzone.addEventListener('dragover', function (e) {

        if (e.preventDefault) {

            e.preventDefault()

        }

        return false

    }, false)

</script>

</body>

</html>


用瀏覽器訪問該頁面。


從上面的例子可以看到FileReader()的基本用法。readAsDataURL()方法用於讀取檔案,它接收一個File 或者Blob物件的例項作為引數,並將檔案內容轉換為一個base64編碼的URL字串,並透過load事件將結果傳遞到e.target.result上。FileReader物件除了readAsDataURL()方法外,還有其他幾個方法用於讀取檔案內容的操作。


(1) readAsArrayBuffer(Blob|File): 讀取檔案,最後result屬性將包含ArrayBuffer物件以表示檔案內容。ArrayBuffer 物件用來表示固定長度二進位制資料的緩衝區。


(2) readAsBinaryString(Blob|File):讀取檔案, result屬性包含檔案的原始二進位制資料。每個位元組均由一個[0.255]範圍內的整數表示。

(3) readAsText(BloblFile,encoding): 以文字方式讀入檔案,並可以指定返回資料的編碼,預設為UTF-8。

(4) abort): 終止正在進行的讀取操作。如果FileReader 物件沒有進行讀取操作,呼叫此方法會丟擲DOM_FILE_ABORT_ERR異常。


2、Blob 物件


以上讀取檔案操作的方法有兩個共同點,一是都接受一個 Blob或File型別的物件。

var fileParts=['<a>hey man</a>'];

var myB1ob=new B1ob (fileParts,{ "type":"text/xml"});


Blob物件還支援slice() 方法,用於對資料進行切割:


var yourBlob = myB1ob.slice (10,20) ;



File物件同樣繼承了Blob的slice()方法,可以利用此方法對File物件預先進行分割,然後再讀取、上傳,最後在伺服器端進行組裝——非同步上傳的原理就是這樣。如果再記住分割點,這樣即使網路中途斷掉,也可以在下次傳輸時從斷點續傳。


除了都接受Blob和File物件,這些方法另外一個共同點是,由於JavaScript本身基於事件驅動,這些和平臺相關的方法都是非同步方法。即呼叫時立即返回,讀取檔案操作完成後再觸發相應的load事件。


除了load事件,FileReader 物件還會呼叫這樣一些事件處理程式。


(1) onabort:當讀取操作被終止時呼叫(呼叫abort 方法)

(2) onerror: 當讀取操作傳送錯誤時呼叫。

(3) onload: 當讀取操作成功完成時呼叫。

(4) onloadend:當讀取操作完成時呼叫,不管是成功還是失敗,該處理程式在onload或者onerror後呼叫。

(5) onloadstart: 當讀取操作將要開始之前呼叫。

(6) onprogress:在讀取資料過程中週期性呼叫。該事件為最有用的事件,在載入較大的檔案時,可以提供一個進度條讓使用者知道當前載入進度,不讓使用者產生焦躁感。


reader.{


   console.log('當前檔案已載入'+ e.loaded/e. total*100.toFixed(2)+'%') 

}


e.total儲存著當前檔案的總大小(位元組),e.loaded 表示當前檔案已經載入了多少。

要想將圖片檔案轉換成可以直接在HTML裡引用的URL,除了前文提到的readAsDataURL()方法,還可以使用window.URL .createObjectURL()方法:


var objectURL =window.URL. crea teObjectURL (file0bj) ;



objectURL最後會得到一個類似blob: null/a672ae4c- f84e- 45d2- -87ae-f45dc986d601的字串,這個字串可以直接被IMG等元素引用。

objectURL和dataURL一樣可以直接被img的src屬性引用,就像Windows平臺下的檔案控制程式碼或者Linux下的檔案描述符,在使用完之後通常還要呼叫window.URL.revokeObjectURL()方法進行釋放,如果不顯示呼叫該方法,objectURL 將會在檔案解除安裝時自動釋放。對於前文的例子可以簡單修改為URL物件版本:

function handleFiles (files) {

   var preview=document.getElementById('preview')

   for(var i=0;i<files.length;i++) {

   var file=files [i]

   ……

   var img=document.createElement("img")

   img.src=window. URL.createObjectURL(file)

   img.{

      window.URL.revoke0bjectURL(this.src)

   }

   Preview. appendChild (img)

   }

}


有了操作檔案的利器,讀者可以做一些有趣的功能,比如實現類似Photoshop中圖片處理的濾鏡或者讀取PDF檔案並轉換為HTML格式等


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69940641/viewspace-2942210/,如需轉載,請註明出處,否則將追究法律責任。

相關文章