4.3 读取文件
通过使用File和FileList对象的相关属性可以获取用户所选择文件的基本信息,除了这两个对象外,HTML 5新增的API中还提供了FileReader对象,该对象是一个接口,它允许在客户端读取文件的数据,并且可以在JavaScript脚本中使用。
4.3.1 认识FileReader接口
FileReader接口专门用来读取文件,根据W3C的定义,它提供一些读取文件的方法与一个包含读取结果的事件模型。它的主要作用是将文件读取到内存,并且提供相应的方法来读取文件中的数据,下面从以下三个方面进行介绍。
1.判断浏览器是否支持FileReader
前面已经提到过,并不是所有的浏览器都提供了对HTML 5功能的支持,FileReader属于HTML 5功能的一部分,因此,在使用FileReader之前,可以检测当前浏览器是否支持FileReader。
判断浏览器是否支持FileReader,如果浏览器支持FileReader接口,那么该浏览器有一个位于Windows对象下的FileReader构造函数,如果这个构造函数存在,那么就可以通过new实例化一个FileReader来使用。检测代码如下。
if ( typeof FileReader == 'undefined' ) { alert( "您的浏览器未实现FileReader接口" ); } else { alert("当前浏览器运行环境正常,能够支持FileReader接口。"); var reader = new FileReader(); //others }
上述代码首先判断浏览器所支持的FileReader是否等于undefined,是或不是都会弹出提示。如果支持FileReader接口,则会创建FileReader的实例对象。当访问不同的文件时,每调用一次FileReader接口都将返回一个新的FileReader对象,这样才会访问不同文件中的数据,因此,必须创建不同的FileReader接口实例对象。
2.FileReader接口的方法
FileReader接口提供了4个方法,其中三个方法用来读取文件,一个方法用来读取中断,方法说明如表4-2所示。
表4-2 FileReader接口的方法
调用表4-2中的方法读取内容时,无论读取文件是否成功,方法都不会返回读取的结果,而是将存储在result属性中,并且result属性只能位于FileReader接口所提供的onload事件中。
3.FileReader接口的事件
FileReader接口中提供了一套完整的事件模型,用于监视读取文件时的各个状态,如表4-3所示。
表4-3 FileReader接口的事件
相关人员调用FileReader接口提供的方法读取文件时,会伴随着发生一系列的事件,它们表示读取文件时不同的读取状态,下面通过一个简单的练习演示FileReader接口的事件执行的先后顺序。
【练习4】
本次练习根据用户选择的图片路径显示图片,并且显示不同浏览器下所执行的事件顺序,步骤如下。
(1)添加并设计新的网页,在页面中添加文件选择框和执行操作的按钮,并且为操作按钮添加事件。代码如下。
选择一个文件:<input type="file" id="selFile" accept="image/jpg" /> <input type="button" id="btnGetFile" value="事件" onClick="GetOper()" />
(2)继续向网页中添加用于处理操作的结果元素,img用来显示图片,ol元素显示事件执行顺序。代码如下。
<img id="myPic" /> <ol id="msgInfo"></ol>
(3)选择文件后单击【事件】按钮触发Click事件调用GetOper()函数,该函数中首先获取用户选择的文件,接着创建FileReader接口实例对象,再调用readAsDataURL()方法读取文件。然后分别为FileReader接口的各个事件添加代码,在onload事件中,通过e.target.result属性的结果值绑定到显示图片的img元素中,在其他事件中直接绑定处理的结果。部分脚本代码如下。
function GetOper() { var file = document.getElementById("selFile").files[0]; var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e){ document.getElementById("myPic").src = e.target.result;//或者this.result获取 document.getElementById("msgInfo").innerHTML += "<li>触发了onload事件。</li>"; } reader.onprogress = function(e){ document.getElementById("msgInfo").innerHTML += "<li>触发了onprogress事件。</li>"; } //省略其他事件的处理 }
(4)不同浏览器由于使用的内核不同,上传图片的大小不同,因此,执行的事件顺序也不会完全相同。选择文件后直接单击【事件】按钮查看事件执行顺序,如图4-13和图4-14所示分别为Maxthon浏览器和Opera浏览器的效果。
图4-13 Maxthon浏览器运行效果
图4-14 Opera浏览器运行效果
从图4-13和图4-14中可以看出,在执行FileReader接口的事件时并不是所有的事件都会执行。针对这些事件,还有一些内容需要注意,说明如下。
(1)大部分的文件读取过程都集中在onprogress事件中,这个事件消耗时间最长。
(2)如果文件在读取过程中出现异常或中止,那么onprogress事件将结束,直接触发onerror或onabort事件,而不再触发onload事件。
(3)onload事件是文件读取成功时触发,而onloadend虽然也是文件操作成功时触发,但该事件不论文件读取是否成功,都将触发。因此,想要正确获取文件数据,必须在onload事件中编写代码。
4.3.2 读取二进制文件
FileReader接口所提供的readAsBinaryString()方法是将文件读取为二进制字符串,通常是将它传送到后端,后端可以通过这段字符串存储文件。
readAsBinaryString()方法的使用很简单,只要将一个要读取的文件file作为参数传入即可,这样读取的结果将保存到result属性中。
【练习5】
本次练习中,用户首先选择一个文件,然后单击页面中的按钮显示二进制文件内容,最后将结果显示到textarea元素中,实现步骤如下。
(1)添加并设计新的网页,在页面的合适位置添加选择文件框,然后分别添加三个按钮元素,分别执行读取二进制文件、读取图像文件和读取文本文件的操作,并且需要为读取二进制文件的按钮添加onClick事件属性。代码如下。
选择文件:<input type="file" id="selFile" /><br/><br/> <input type="button" id="btnGetBinaryFileInfo" value="读取二进制文件" onClick="GetBinaryFile()" /> <input type="button" id="btnGetPicInfo" value="读取图像文件" /> <input type="button" id="btnGetFileInfo" value="读取文本文件" />
(2)GetBinaryFile()函数用来读取选择文件的二进制内容,首先获取用户选择的文件对象,通过判断对象是否为空确定是否选择了文件。如果选择了文件则创建FileReader接口的对象,然后将file对象作为参数传入所调用的readAsBinaryString()方法中,并且在onload事件中获取返回的结果。代码如下。
function GetBinaryFile() { var file = document.getElementById("selFile").files[0]; if(file==null || file=='undefined'){ //判断是否选择了文件,没有选择 alert("您还没有选择文件,请选择文件。"); }else{ //如果选择了文件 var reader = new FileReader(); reader.readAsBinaryString(file); reader.onload = function(e){ document.getElementById("readResult").innerHTML = this.result; } } }
(3)运行页面选择文件查看效果,其中,程序文件、文本文件、图像和压缩包等都属于二进制文件。如图4-15所示为Maxthon浏览器下读取压缩包的二进制文件,如图4-16所示为Firefox浏览器下读取图像的二进制文件。
图4-15 Maxthon浏览器运行效果
图4-16 Firefox浏览器运行效果
试一试
另外,同一个文件在不同的浏览器所读取出的二进制文件的内容会有所不同,在Opera浏览器下读取的内容都非常简短,感兴趣的读者可以进行测试。
4.3.3 显示预览图像
FileReader接口所提供的readAsDataURL()方法将文件读取为一段以data开头的字符串,这段字符串实质上就是DataURL,即一种将小文件直接嵌入文档的方案,小文件通常是指图像与html等格式的文件。
【练习6】
本次练习主要调用FileReader接口的readAsDataURL()方法,不通过后台而即时实现图片预览的功能,其中允许用户选择多个图片文件,单击按钮提交后将显示这些文件的缩略效果图。
(1)继续更改练习5中的页面,首先将文件选择框的multiple属性的值设置为true,然后向名称是“读取图像文件”的按钮中添加onClick事件属性。代码如下。
选择文件:<input type="file" id="selFile" multiple="true" /><br/><br/> <input type="button" id="btnGetBinaryFileInfo" value="读取二进制文件" onClick="GetBinaryFile()" disabled /> <input type="button" id="btnGetPicInfo" value="读取图像文件" onClick="GetPicFile()" /> <input type="button" id="btnGetFileInfo" value="读取文本文件" />
(2)删除用于显示二进制文件内容的textarea元素,向页面中添加显示图片列表的span元素。代码如下。
<span id="showInfo"></span>
(3)GetPicFile()文件获取用户选择的文件,并且进行判断,如果选择的文件符合是图像的要求,则将其显示到页面中,否则会弹出提示。代码如下。
function GetPicFile() { var filelist = document.getElementById("selFile"); //获取选择的文件 if(filelist.files.length==0) //如果选择文件列表为空 { alert("请选择您要查看的图像"); }else{ for (var i = 0; i < filelist.files.length; i++) {//循环显示文件 var file = filelist.files[i]; //获取单个文件 var imageType = /image.*/; //声明文件类型 if (!file.type.match(imageType)) { //如果上传文件不合法 alert(file.name+"不是图像文件,因此不能上传。"); continue; } var reader = new FileReader(); //实例FileReader接口对象 reader.onload = function(e){ //显示图像 document.getElementById("showInfo").innerHTML += "<img src="+e.target.result+" width=200 height=150 style='padding-right:50px; padding-bottom:20px;' />"; }; reader.readAsDataURL(file); } } }
(4)运行页面查看效果,所有图像选择完成后单击【读取图像文件】按钮进行预览查看,效果如图4-17所示。
图4-17 显示预览图像的效果
4.3.4 读取文本文件
除了readAsBinaryString()方法和readAsDataURL()方法外,FileReader接口还提供了一种读取文件的方法——readAsText()方法。readAsText()方法专门用来读取文本文件,该方法常用的参数有两个:第一个参数是file类型,表示要读取的文件;第二个参数是字符串类型,表示读取文件时使用的编码,默认值是UTF-8。
【练习7】
本练习通过使用readAsText()方法实现读取用户选择文本文件内容的功能,其文件选择框与练习5一样,一次只允许用户选择一个文件进行读取,实现步骤如下。
(1)添加并设计新的页面,更改或重新添加页面的内容。如下代码演示了文件框执行操作。
选择文件:<input type="file" id="selFile" /><br/><br/> <input type="button" id="btnGetFileInfo" value="读取文本文件" onClick="GetFile()" />
(2)练习6中通过指定span元素的有关属性的值预览图片,本次练习继续使用span元素显示内容,相关代码不再显示。
(3)JavaScript脚本中的GetFile()函数实现了文本文件内容的读取,在该函数中首先判断用户是否选择文件,如果没有选择文件则弹出提示。如果已经选择了文件,则在else语句中判断所选择的文件是否符合类型,如果不符合则弹出提示,否则在FileReader接口的onload事件中指定显示的内容。GetFile()函数的代码如下。
function GetFile() { var file = document.getElementById("selFile").files[0]; if(file==null || file=='undefined'){ //如果没有选择文件 alert("您还没有选择文件,请选择文件。"); }else{ var txtType = /text.*/; if (!file.type.match(txtType)) { //如果选择的文件不符合类型 alert(file.name+"不是文本文件,请重新选择文件进行上传。") return; } var reader = new FileReader(); reader.readAsText(file); reader.onload = function(e){ //显示文件内容 document.getElementById("showInfo").innerHTML = this.result; } } }
(4)运行页面,在多个浏览器中选择文件进行测试。这些浏览器由于文件编码、页面编码以及兼容性等问题,可能会导致所读取的文件有的浏览器能正常显示,有些浏览器则显示乱码,如图4-18和图4-19所示分别了Maxthon浏览器和Firefox浏览器中的效果。
图4-18 Maxthon浏览器读取文本文件
图4-19 Firefox浏览器读取文本文件
(5)重新向GetFile()函数中添加内容,在readAsText()方法的第二个参数中指定编码格式。代码如下。
reader.readAsText(file,"gb2312");
(6)重新在各个浏览器中选择文件进行测试,如图4-20和图4-21所示分别为Maxthon浏览器和Opera浏览器编码后的效果。
图4-20 编码后Maxthon浏览器效果
图4-21 编码后Opera浏览器效果
(7)在GetFile()函数中通过txtType变量声明文本文件类型,文本文件类型常见的有两种形式:一种是“text/plain”格式的文件,通常以.txt结尾;另一种是“text/html”文件,以.html结尾。如图4-22所示显示了读取某磁盘下File Reader.html文件在Opera浏览器中的显示效果,注意编码格式。
图4-22 读取.html格式的文本文件