Html5 檔案上傳

gary-liu發表於2016-09-30

拖拽目錄只有chrome11及以後版本才支援,也可直接看參考文獻中的文章,本文主要記錄自己做過的一些東西
這有個簡單的 html5 上傳demo:https://github.com/xiaoshenge/html5demo/blob/master/file/js/list.js

HTML5 提供了一種通過 File API 規範與本地檔案互動的標準方式。為了舉例說明其功能,可使用 File API 在向伺服器傳送圖片的過程中建立圖片的縮圖預覽,或者允許應用程式在使用者離線時儲存檔案引用。另外,可以使用客戶端邏輯來驗證上傳內容的 mimetype 與其副檔名是否匹配,或者限制上傳內容的大小。
該規範通過“本地”檔案系統提供了多種檔案訪問介面:

  1. File - 獨立檔案;提供只讀資訊,例如名稱、檔案大小、mimetype 和對檔案控制程式碼的引用。
  2. FileList - File 物件的類陣列序列(考慮 <input type="file" multiple> 或者從桌面拖動目錄或檔案)。
  3. Blob - 可將檔案分割為位元組範圍。

與以上資料結構結合使用時,FileReader 介面可用於通過熟悉的 JavaScript 事件處理來非同步讀取檔案。因此,可以監控讀取進度、找出錯誤並確定載入何時完成。這些 API 與 XMLHttpRequest 的事件模型有很多相似之處。

判斷瀏覽器是否完全支援 File API

// Check for the various File API support.
if (window.File && window.FileReader && window.FileList && window.Blob) {
  // Great success! All the File APIs are supported.
} else {
  alert('The File APIs are not fully supported in this browser.');
}

使用上傳按鈕上傳檔案

<input type="file" id="files" name="files[]" multiple />
<output id="list"></output>

<script type="text/javascript">
    function handleFileSelect(evt) {
        var files = evt.target.files;
        var output = [];
        for (var i = 0, f; f = files[i]; i++) {
            output.push('<li><strong>', escape(f.name), '</strong> (', f.type || 'n/a', ') - ',
                f.size, ' bytes, last modified: ',
                f.lastModifiedDate.toLocaleDateString(), '</li>');
        }
        document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
    }
    document.getElementById('files').addEventListener('change', handleFileSelect, false);
</script>

拖拽的方式上傳檔案

<div class="example">
    <div id="drop_zone">將檔案拖放到此處</div>
    <output id="list"></output>
</div>

<script type="text/javascript">
    var fileList = null; //傳輸的檔案
    function handleFileSelect(evt) {

        evt.stopPropagation();
        evt.preventDefault();
        //add
        evt.target.className = (evt.type == "dragover" ? "hover" : "");
        fileList = evt.target.files || evt.dataTransfer.files; // FileList object.

        //console.log(evt);
        //console.log(fileList);
        // files is a FileList of File objects. List some properties.
        var output = [];
        for (var i = 0, f; f = fileList[i]; i++) {
            if (!f.name.startsWith('.')) {
                console.log(f);
            }
            output.push('<li><strong>', f.name, '</strong> (', f.type || 'n/a', ') - ',
                f.size, ' bytes, last modified: ',
                f.lastModifiedDate.toLocaleDateString(),
                '<div id="progressNumber', i, '" style="float:right">', '</div>',
                '</li>');
        }
        document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
    }

    function handleDragOver(evt) {
        evt.stopPropagation();
        evt.preventDefault();
        evt.dataTransfer.dropEffect = 'copy'; // Explicitly show this is a copy.
    }

    // Setup the dnd listeners.
    var dropZone = document.getElementById('drop_zone');
    dropZone.addEventListener('dragover', handleDragOver, false);
    dropZone.addEventListener('drop', handleFileSelect, false);
</script>

這個也可以上傳目錄,不過目前只有chrome11及以後版本支援

使用按鈕上傳目錄

<div id="addfilediv">
    <label class="addfolder">
        <input type="file" id="folderInput" multiple="true" webkitdirectory="true" directory="true" style="top: -0.5px; left: -40px; " />
    </label>
    <lable id="notice">*上傳目錄</lable>
</div>

<script type="text/javascript">
    var fileList = null; //傳輸的檔案
    var folderInput = document.getElementById('folderInput');

    function handleFileSelect(evt) {

        evt.stopPropagation();
        evt.preventDefault();
        //add
        evt.target.className = (evt.type == "dragover" ? "hover" : "");
        fileList = evt.target.files || evt.dataTransfer.files; // FileList object.

        //console.log(evt);
        //console.log(fileList);
        // files is a FileList of File objects. List some properties.
        var output = [];
        for (var i = 0, f; f = fileList[i]; i++) {
            if (!f.name.startsWith('.')) {
                console.log(f);
            }
            output.push('<li><strong>', f.name, '</strong> (', f.type || 'n/a', ') - ',
                f.size, ' bytes, last modified: ',
                f.lastModifiedDate.toLocaleDateString(),
                '<div id="progressNumber', i, '" style="float:right">', '</div>',
                '</li>');
        }
        document.getElementById('list').innerHTML = '<ul>' + output.join('') + '</ul>';
    }

    folderInput.addEventListener('change', handleFileSelect, false);
</script>

當獲取了 File 引用後,例項化 FileReader 物件,以便將其內容讀取到記憶體中。載入結束後,將觸發讀取程式的 onload 事件,而其 result 屬性可用於訪問檔案資料。
FileReader 讀取檔案:
FileReader.readAsBinaryString(Blob|File) - result 屬性將包含二進位制字串形式的 file/blob 資料。每個位元組均由一個 [0..255] 範圍內的整數表示。

對 FileReader 物件呼叫其中某一種讀取方法後,可使用 onloadstart、onprogress、onload、onabort、onerror 和 onloadend 跟蹤其進度。

[參考文獻]

通過 File API 使用 JavaScript 讀取檔案

相關文章