今天在寫前端的時候碰到一些問題,如今對於web網頁操做文件進一步瞭解。html
主要參照:http://www.cnblogs.com/zichi/p/html5-file-api.html前端
FileList 對象針對表單的 file 控件。當用戶經過 file 控件選取文件後,這個控件的 files 屬性值就是 FileList 對象。它在結構上相似於數組,包含用戶選取的多個文件。若是 file 控件沒有設置 multiple 屬性,那麼用戶只能選擇一個文件,FileList 對象也就只有一個元素了。html5
<input type='file' multiple/> <script> document.querySelector('input').onchange = function () { console.log(this.files); }; </script>
控制檯輸出文件相關內容。git
上圖中咱們看到,File 對象是繼承自 Blob 對象的,Blob 又是什麼鬼?github
Blob(Binary Large Object)對象表明了一段二進制數據,提供了一系列操做接口。其餘操做二進制數據的 API(好比 File 對象),都是創建在 Blob 對象基礎上的,繼承了它的屬性和方法。web
生成 Blob 對象有兩種方法:一種是使用 Blob 構造函數,另外一種是對現有的 Blob 對象使用 slice 方法切出一部分。canvas
(1)Blob 構造函數,接受兩個參數。第一個參數是一個包含實際數據的數組,第二個參數是數據的類型,這兩個參數都不是必需的。後端
var a = ["hello", "world"]; var myBlob = new Blob(a, { "type" : "text/xml" }); console.log(myBlob);
(2)Blob 對象的 slice 方法,將二進制數據按照字節分塊,返回一個新的 Blob 對象。api
var a = ["hello", "world"]; var myBlob = new Blob(a, { "type" : "text/xml" }); var newBlob = myBlob.slice(0, 5); console.log(newBlob);
Blob 對象有兩個只讀屬性:數組
重頭戲來了,FileReader API 纔是咱們接下去完成一些任務的關鍵。FileReader API 用於讀取文件,即把文件內容讀入內存。它的參數是 File 對象或 Blob 對象。
對於不一樣類型的文件,FileReader 提供不一樣的方法讀取文件。
除了以上四種不一樣的讀取文件方法,FileReader API 還有一個 abort 方法,用於停止文件上傳。
var reader = new FileReader(); reader.abort();
FileReader 對象採用異步方式讀取文件,能夠爲一系列事件指定回調函數。
之前在學習圖片的 base64 編碼的時候,寫了一篇文章 獲取圖片 base64 編碼的幾種方法,當時尚未學習 File API,瞭解到 File API 也能作相似的事情,如今學到了,寫了個簡單的 demo http://hanzichi.github.io/2016/image2base64/,不只能獲取圖片的 base64 編碼,同時也能獲取文字的 base64 編碼,代碼比較簡單就不放了,能夠 猛戳這裏。
獲取到了文件的 base64 編碼,作一些諸如圖片預覽的功能,也就手到擒來了,有興趣的能夠本身嘗試下,相似的還有文字預覽啊,等等。
你覺得 File API 就這樣了嗎?非也,還有個強大的東西沒有介紹,URL 對象!
調用 URL 對象的 createObjectURL 方法,傳入一個 File 對象或者 Blob 對象,能生成一個連接,聽起來好像很吊的樣子。
var objecturl = window.URL.createObjectURL(blob);
上面的代碼會對二進制數據生成一個 URL,這個 URL 能夠放置於任何一般能夠放置 URL 的地方,好比 img 標籤的 src 屬性。須要注意的是,即便是一樣的二進制數據,每調用一次 URL.createObjectURL 方法,就會獲得一個不同的 URL。
這個 URL 的存在時間,等同於網頁的存在時間,一旦網頁刷新或卸載,這個 URL 就失效。(File 和 Blob 又未嘗不是這樣呢)除此以外,也能夠手動調用 URL.revokeObjectURL 方法,使 URL 失效。
window.URL.revokeObjectURL(objectURL);
舉個簡單的例子。
var blob = new Blob(["Hello hanzichi"]); var a = document.createElement("a"); a.href = window.URL.createObjectURL(blob); a.download = "a.txt"; a.textContent = "Download"; document.body.appendChild(a);
頁面上生成了一個超連接,點擊它就能下載一個名爲 a.txt
的文件,裏面的內容是 Hello hanzichi
。
這裏插點題外話,簡單介紹下 H5 新增的 download 屬性。對於一些諸如 exe,rar 等瀏覽器不能直接打開的文件類型,咱們通常能夠直接用一個 a 標籤,將其指向文件在服務端的地址,點擊便可下載。可是若是是一些瀏覽器能直接打開的文件,好比 txt,js 等,若是這樣設置一個超連接,點擊會直接打開文件,通常咱們能夠配合後端實現,好比用 PHP。
$file_name = "1.txt"; // 下載文件名 $file_dir = dirname(__FILE__). '/'; //下載文件存放目錄 //輸入文件標籤 Header("Content-type: text/plain"); Header("Content-Disposition: attachment; filename=" . $file_name );
以上代碼須要文件的 Content-type 屬性值,安利一個網址,http://tool.oschina.net/commons ,各類文件類型的 Content-type 屬性值一網打盡!
若是考慮到安全性,header + fread 可能會顯得更嚴謹。
$file_name = "1.txt"; // 下載文件名 $file_dir = dirname(__FILE__). '/'; //下載文件存放目錄 Header("Content-type: text/plain"); Header("Content-Disposition: attachment; filename=" . $file_name ); echo fread($file, filesize($file_dir . $file_name));
可是如今咱們只須要在 a 標籤上加上 download !
<a href="1.txt" download>download txt></a>
還能夠給 download 加上屬性值,即爲下載的文件名。
<a href="1.txt" download="2.txt">download txt></a>
能夠省略 .txt
的後綴名,瀏覽器會自行判斷。
咱們再回到 URL 上來。對於 File 或者 Blob 對象,咱們能夠這樣理解,它們的存在,依賴於頁面,而 URL 能給這些 "轉瞬即逝" 的二進制對象一個臨時的指向地址。
這個臨時的地址還有什麼用呢?也能作圖片預覽,相比前面用 readAsDataURL 的實現,更簡單了。
<input type='file' multiple /><br/> <img /> <script> document.querySelector("input").onchange = function() { var files = this.files; document.querySelector("img").src = window.URL.createObjectURL(files[0]); } </script>
好比還有這樣的需求,前端上傳文件,要動態生成該文件的下載連接,也能用 URL 完成。
canvas 中有 toDataURL 函數,能夠將 canvas 轉爲 dataURL 形式的 base64 編碼,而 Blob 也能夠轉爲 dataURL,這三者之間是否能夠互相轉換?有沒有什麼實用之處?
(1)canvas -> dataURL
用 toDataURL 方法,比較簡單,很少說。
(2)blob -> dataURL
用 FileReader 的 readAsDataURL 方法,使用方式能夠看 這個 demo
(3)dataURL -> blob
這個函數有點屌
function dataURLtoBlob(dataurl) { var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new Blob([u8arr], {type:mime}); }
(4)dataURL - canvas
將 image 的 src 屬性置爲 dataURL,再用 drawImage 方法畫上去。
(5)blob - canvas
如何把二進制形式的圖片畫上 canvas?先用 readAsDataURL 轉爲 dataURL,接着就是 (4) 的事情了。
(6)canvas - blob
canvas 轉爲 blob 也能夠用 dataURL 作跳板,先將 canvas 轉爲 dataURL(1),再用 dataURL 轉爲 blob(3)。
利用它們之間的轉換能夠作些什麼好玩的事呢?好比能夠上傳圖片,對圖片作各類處理,而後保存,看起來好像挺好玩的,等有空了搞個 demo 出來。
2016.11.11 add: canvas 有原生的 toBlob 方法,使得圖片文件能夠被緩存或保存到本地。