本地文件,本地文件管理,HTML5读取本地文件
一旦调用了以上某个方法读取文件后,我们可以监听以上任何一个事件来获得进度、结果等。
预览本地图片这里主要用到FileReader的readAsDataURL方法,通过将图片数据读取成Data URI的方法,将图片展示出来。
function fileSelect2(e) { e = e || window.event; var files = this.files; var p = document.getElementById('preview2'); for(var i = 0, f; f = files[i]; i++) { var reader = new FileReader(); reader.onload = (function(file) { return function(e) { var span = document.createElement('span'); span.innerHTML = ' img width="100" src="'+ this.result +'" alt="'+ file.name +'" / '; p.insertBefore(span, null); })(f); //读取文件内容 reader.readAsDataURL(f); document.getElementById('files2').addEventListener('change', fileSelect2, false);
调用FileReader的readAsDataURL接口时,浏览器将异步读取文件内容,通过给FileReader实例监听一个onload事件,数据加载完毕后,在onload事件处理中,通过reader的result属性即可获得文件内容。
预览文本文件这里主要用到FileReader的readAsText,对于诸如mimeType为text/plain、text/html等文件均认为是文本文件,即mineType为text开头都可以用这个方法来预览。
function fileSelect3(e) { e = e || window.event; var files = this.files; var p = document.getElementById('preview3'); for(var i = 0, f; f = files[i]; i++) { var reader = new FileReader(); reader.onload = (function(file) { return function(e) { var div = document.createElement('div'); div.className = "text" div.innerHTML = encodeHTML(this.result); p.insertBefore(div, null); })(f); //读取文件内容 reader.readAsText(f); document.getElementById('files3').addEventListener('change', fileSelect3, false);
PS:由于需要在页面上预览文本,所以则需要对文件中的html特殊字符进行实体编码,避免浏览器解析文件中的html代码。
监控读取进度既然FileReader是异步读取文件内容,那么就应该可以监听它的读取进度。
事实上,FileReader的onloadstart以及onprogress等事件,可以用来监听FileReader的读取进度。
在onprogress的事件处理器中,有一个ProgressEvent对象,这个事件对象实际上继承了Event对象,提供了三个只读属性:
lengthComputable loaded total通过以上几个属性,即可实时显示读取进度,不过需要注意的是,此处的进度条是针对单次读取的进度,即一次readAsBinaryString等方法的读取进度。
var input4 = document.getElementById('file4'); var bar = document.getElementById('progress-bar'); var progress = document.getElementById('progress'); function startHandler(e) { bar.style.display = 'block'; function progressHandler(e) { var percentLoaded = Math.round((e.loaded / e.total) * 100); if (percentLoaded 100) { progress.style.width = percentLoaded + '%'; progress.textContent = percentLoaded + '%'; function loadHandler(e) { progress.textContent = '100%'; progress.style.width = '100%'; function fileSelect4(e) { var file = this.files[0]; if(!file) { alert('请选择文件!'); return false; if(file.size 500 * 1024 * 1024) { alert('文件太大,请选择500M以下文件,防止浏览器崩溃!'); return false; progress.style.width = '0%'; progress.textContent = '0%'; var reader = new FileReader(); reader.onloadstart = startHandler; reader.onprogress = progressHandler; reader.onload = loadHandler; reader.readAsBinaryString(this.files[0]); input4.onchange = fileSelect4;
有的时候,一次性将一个大文件读入内存,并不是一个很好的选择(如果文件太大,可能直接导致浏览器崩溃),上述的监听进度示例就有可能在文件太大的情况下崩溃。
更稳健的方法是分段读取!
分段读取文件HTML5 File Api提供了一个slice方法,允许分片读取文件内容。
function readBlob(start, end) { var files = document.getElementById('file5').files; if(!files.length) { alert('请选择文件'); return false; var file = files[0], start = parseInt(start, 10) || 0, end = parseInt(end, 10) || (file.size - 1); var r = document.getElementById('range'), c = document.getElementById('content'); var reader = new FileReader(); reader.onloadend = function(e) { if(this.readyState == FileReader.DONE) { c.textContent = this.result; r.textContent = "Read bytes: " + (start + 1) + " - " + (end + 1) + " of " + file.size + " bytes"; var blob; if(file.webkitSlice) { blob = file.webkitSlice(start, end + 1); } else if(file.mozSlice) { blob = file.mozSlice(start, end + 1); } else if(file.slice) { blob = file.slice(start, end + 1); reader.readAsBinaryString(blob); document.getElementById('file5').onchange = function() { readBlob(10, 100); }
本例使用了FileReader的onloadend事件来检测读取成功与否,如果用onloadend则必须检测一下FileReader的readyState,因为read abort时也会触发onloadend事件,如果我们采用onload,则可以不用检测readyState。
分段读取进度那分段读取一个大文件时,如何监控整个文件的读取进度呢?
这种情况下,因为我们调用了多次FileReader的文件读取方法,跟上文一次性把一个文件读到内存中的情况不大相同,不能用onprogress来监控。
我们可以监听onload事件,每次onload代表每个片段读取完毕,我们只需要在onload中计算已读取的百分比就可以了!
var bar2 = document.getElementById('progress-bar2'); var progress2 = document.getElementById('progress2'); var input6 = document.getElementById('file6'); var block = 1 * 1024 * 1024; // 每次读取1M // 当前文件对象 var file; // 当前已读取大小 var fileLoaded; // 文件总大小 var fileSize; // 每次读取一个block function readBlob2() { var blob; if(file.webkitSlice) { blob = file.webkitSlice(fileLoaded, fileLoaded + block + 1); } else if(file.mozSlice) { blob = file.mozSlice(fileLoaded, fileLoaded + block + 1); } else if(file.slice) { blob = file.slice(fileLoaded, fileLoaded + block + 1); } else { alert('不支持分段读取!'); return false; reader.readAsBinaryString(blob); // 每个blob读取完毕时调用 function loadHandler2(e) { fileLoaded += e.total; var percent = fileLoaded / fileSize; if(percent 1) { // 继续读取下一块 readBlob2(); } else { // 结束 percent = 1; percent = Math.ceil(percent * 100) + '%'; progress2.innerHTML = percent; progress2.style.width = percent; function fileSelect6(e) { file = this.files[0]; if(!file) { alert('文件不能为空!'); return false; fileLoaded = 0; fileSize = file.size; bar2.style.display = 'block'; // 开始读取 readBlob2(); var reader = new FileReader(); // 只需监听onload事件 reader.onload = loadHandler2; input6.onchange = fileSelect6
在chrome浏览器上测试时,如果直接以file://xxx这种形式访问demo,会出现FileReader读取不到内容的情况,表现为FileReader的result为空或者FileReader根本就没有去读取文件内容,FileReader各个事件没有触发;
这种情况我想应该是类似于chrome不允许添加本地cookie那样,chrome也不允许以file://xxx这种页面上的js代码访问文件内容;
解决办法很简单,只需要将测试文件放到一个web服务器上,以http://xxx形式访问即可。
http://www.html5rocks.com/en/tutorials/file/dndfiles/转:http://hushicai.com/2014/03/29/html5-du-qu-ben-di-wen-jian.html