本文整理了兼容性检测、文件选择、属性读取、文件读取、进度监控、大文件分片上传以及拖拽上传等开拓中常见的前端文件操作。

准备事情

首先,我们的 File 来自于 <input> 标签中选中的文件列表。
以是,准备如下的 HTML 代码

<input type=\"大众file\"大众 id=\"大众files\"大众 multiple /><div id=\"大众list\公众></div><div id=\公众images\"大众></div><!-- File API干系操作写在了script.js中 --><script src=\"大众./script.js\"大众></script>检测兼容性

File 工具是分外类型的 Blob。
在 script 入口处,该当检测当前浏览器是否支持 File API:

转载html5的fileapi应用HTML5 进阶FileAPI 文件操作实战内附具体案例建议珍藏 React

if (!(window.File && window.FileReader && window.FileList && window.Blob)) { throw new Error(\公众当前浏览器对FileAPI的支持不完善\公众);}监听文件选择

对付 type 为 file 类型的 <input> 标签,在选择文件的时候,会触发 change 事宜。
用户选中的文件信息也会传入回调函数的第一个参数中。

function handleFileSelect(event) { const { files } = event.target; if (!files.length) { console.log(\"大众没有选择文件\"大众); return; } console.log(\公众选中的文件信息是:\"大众, files);}document .querySelector(\公众#files\"大众) .addEventListener(\公众change\"大众, handleFileSelect, false);文件属性-File

event.target.files 是一个 FileList 工具,它是一个由 File 工具组成的列表。

每个 File 工具,保存着选中的对应文件的属性。
常用的用:

name:文件名type:文件类型size:文件大小

下面,通过 type 属性,过滤掉非图片类型的文件,只展示图片类型文件的信息:

function handleFileSelect(event) { const { files } = event.target; if (!files.length) { console.log(\"大众没有选择文件\公众); return; } const innerHTML = []; const reImage = /image./; for (let file of files) { if (!reImage.test(file.type)) { continue; } innerHTML.push( ` <li> <strong>${file.name}</strong> (${file.type || \"大众n/a\公众}) - ${file.size} bytes </li> ` ); } document.querySelector(\公众#list\"大众).innerHTML = `<ul>${innerHTML.join(\"大众\"大众)}</ul>`;}

FileReader

读取文件-FileReader

还是以图片读取为例,读取并且显示所有的图片类型文件。

文件读取须要利用 FileReader 工具,它常用 3 个回调方法:

onload: 文件读取完成onloadstart:文件上传开始onprogress : 文件上传中触发

和Image类似,在读取文件之前,须要先绑定事宜处理。
它读取操作有:readAsArrayBuffer、readAsDataURL、readAsBinaryString、readAsText。
传入的参数便是 File 工具。

那么这几个方法有什么差异呢?不同的读取办法,回调事宜onload接管到的event.target.result不相同。
比如,readAsDataURL 读取的话,result 是一个图片的 url。

下面便是读取图片文件,然后展示的一个例子:

function handleFileSelect(event) { let { files } = event.target; if (!files.length) { return; } let vm = document.createDocumentFragment(), re = /image./, loaded = 0, // 完成加载的图片数量 total = 0; // 统共图片数量 // 统计image文件数量 for (let file of files) { re.test(file.type) && total++; } // onloadstart回调 const handleLoadStart = (ev, file) => console.log(`>>> Start load ${file.name}`); // onload回调 const handleOnload = (ev, file) => { console.log(`<<< End load ${file.name}`); const img = document.createElement(\"大众img\"大众); img.height = 250; img.width = 250; img.src = ev.target.result; vm.appendChild(img); // 完成加载后,将其放入dom元素中 if (++loaded === total) { document.querySelector(\公众#images\"大众).appendChild(vm); } }; for (let file of files) { if (!re.test(file.type)) { continue; } const reader = new FileReader(); reader.onloadstart = ev => handleLoadStart(ev, file); reader.onload = ev => handleOnload(ev, file); // 读取文件工具 reader.readAsDataURL(file); }}document .querySelector(\"大众#files\公众) .addEventListener(\"大众change\"大众, handleFileSelect, false);监控读取进度

在监控读取进度的时候,紧张是处理 FileReader 工具上的 onprogress 事宜。

下面的例子,请打开一个较大的文件来查看效果(否则一下就读取完了):

function handleFileSelect(event) { let { files } = event.target; if (!files.length) { return; } const handleLoadStart = (ev, file) => console.log(`>>> Start load ${file.name}`); const handleProgress = (ev, file) => { if (!ev.lengthComputable) { return; } // 打算进度,并且以百分比形式展示 const percent = Math.round((ev.loaded / ev.total) 100); console.log(`<<< Loding ${file.name}, progress is ${percent}%`); }; for (let file of files) { const reader = new FileReader(); reader.onloadstart = ev => handleLoadStart(ev, file); reader.onprogress = ev => handleProgress(ev, file); reader.readAsArrayBuffer(file); }}document .querySelector(\公众#files\"大众) .addEventListener(\公众change\"大众, handleFileSelect, false);

slice

大文件分片读取

在对付超大文件,一样平常采取分片上传的思路办理。
文章开头有讲到,File 是 Blob 的一个特例。
而 Blob 上有一个 slice (https://developer.mozilla.org/zh-CN/docs/Web/API/Blob/slice)方法,通过它,前端就可以实现分片读取大文件的操作。

为了方便解释,请先准备好一个 txt 文件,文件内容便是:hello world。

示例代码如下,代码中只读取前 5 个字节,由于每个英笔墨母占 1 个字节,以是打印结果该当是“hello”。

function handleFileSelect(event) { let { files } = event.target; if (!files.length) { return; } // 为了方便解释,这里仅仅读取第一个文件 const file = files[0]; // 读取前5个字节的内容 const blob = file.slice(0, 5); const reader = new FileReader(); // 掌握台输出结果该当是:hello reader.onload = ev => console.log(ev.target.result); reader.readAsText(blob);}document .querySelector(\"大众#files\"大众) .addEventListener(\"大众change\"大众, handleFileSelect, false);拖拽上传

和前面所述的 File API 干系是完备一样的。
唯一须要分外处理的是文件工具的获取入口改变了。
对付 <input> 标签,监听 onchange 事宜,FileList 存放在 event.target.files 中;对付拖拽操作,FileList 存放在拖拽事宜的回调函数参数里,通过 event.dataTransfer.files 访问即可。

须要修正一下 html 代码:

<!DOCTYPE html><head> <meta charset=\"大众UTF-8\"大众> <style> #container { width: 300px; height: 300px; border: 3px dotted red; } </style></head><body> <div id=\公众container\"大众></div> <script src=\"大众./script.js\"大众></script></body></html>

脚本文件的代码如下:

function handleDropover(event) { event.stopPropagation(); event.preventDefault();}function handleDrop(event) { event.stopPropagation(); event.preventDefault(); / 访问拖拽文件 / const files = event.dataTransfer.files; console.log(files); //}const target = document.querySelector(\"大众#container\"大众);target.addEventListener(\公众dragover\"大众, handleDropover);target.addEventListener(\"大众drop\"大众, handleDrop);后审察干

后审察干超出了本文的谈论范围,可以参考这篇文章(https://github.com/purplebamboo/blog/issues/17)。

版权

作者:心谭

链接:https://juejin.im/post/5d35af63e51d454fa33b199e

著作权归作者所有。

关注

感谢阅读,如果这篇文章对你又帮助,记得 点赞 ,收藏,转发 哟。

期待下次与你相遇 :)