今天在写前端的时候碰到一些问题,如今对于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 方法,使得图片文件能够被缓存或保存到本地。