转载至 : http://www.360doc.com/content/14/0214/18/1457948_352511645.shtml
FileReader 资料(英文): https://developer.mozilla.org/en-US/docs/Web/API/FileReader#State_constants
前面本博介绍了File API,这里将继续介绍一下FileReader,用FileReader具体地读取文件内容。
一、FileReader读取文件内容
File API一文中主要介绍获取文件句柄的方法,接下来我们就要利用该文件句柄来读取文件内容,这是通过FileReader来实现的,通过FileReader接口,我们可以异步地将文件内容加载到内存中,赋予某个js变量。
FileReader具体支持哪些方法和事件,这里就不介绍了,有兴趣的可以去w3c官网上看看FileReader介绍,这里主要介绍一下FileReader两个常见应用。
1、预览本地图片
这里主要用到FileReader的readAsDataURL方法,通过将图片数据读取成Data URL的方法,将图片展示出来,关于DATA URI。
示例脚本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
function fileSelect(e) {
e = e ||
window.event;
var files
= e.target.files; //FileList
Objects
var ireg
= /image\/.*/i,
p
=
document.getElementById( ‘Preview‘ );
var ul =
document.getElementById( ‘Errors‘ );
for ( var i
= 0, f; f = files[i]; i++) {
if (!f.type.match(ireg))
{
//设置错误信息
var li
= document.createElement( ‘li‘ );
li.innerHTML
= ‘<li>‘ + f.name
+ ‘不是图片文件.</li>‘ ;
ul.appendChild(li);
continue ;
}
var reader
= new FileReader();
reader.onload
= ( function (file) {
return function (e)
{
var span
= document.createElement( ‘span‘ );
span.innerHTML
= ‘<img class="thumb"
src="‘ + this .result + ‘"
alt="‘ + file.name + ‘"
/>‘ ;
p.insertBefore(span, null );
};
})(f);
//读取文件内容
reader.readAsDataURL(f);
}
} if (window.File && window.FileList
&& window.FileReader && window.Blob) {
document.getElementById( ‘Files‘ ).addEventListener( ‘change‘ ,
fileSelect, false );
} else {
document.write( ‘您的浏览器不支持File
Api‘ );
} |
由以上代码可知,调用FileReader的readAsDataURL接口,将启动异步加载文件内容,通过给reader监听一个onload事件,将数据加载完毕后,在onload事件处理中,通过reader的result属性即可获得文件内容,查看示例>>。
NOTE:在示例中,我给图片指定了一个height:75px的css样式,主要是为了让浏览器对图片进行等比缩放处理,所以在浏览器中展示出来的图片并不是原始大小的图片,而是经过浏览器自动等比缩放的图片;如果需要查看原始尺寸图片,可点击相应图片;再次单击该图片,则恢复小图片。
2、预览文本文件
这里主要用到FileReader的readAsText,对于诸如mimetype为text/plain、text/html等文件均认为是文本文件,即minetype为text开头都能在本例中预览。
NOTE:由于需要在页面上预览文本,如果使用innerHTML插入文本的话,则需要对html中一些特殊字符进行实体编码,这样才能保证正常显示文本。
简易的encodeHTML方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
function encodeHTML(source) {
return source
.replace(/&/g, ‘&‘ )
.replace(/</g, ‘<‘ )
.replace(/>/g, ‘>‘ )
.replace(/ "/,
‘" ‘)
.replace(/ ‘/,
‘ ‘‘ );
}; function fileSelect(e) {
e = e ||
window.event;
var files
= e.target.files; //FileList
Objects
var ireg
= /text\/.*/i,
p
=
document.getElementById( ‘Preview‘ );
var ul =
document.getElementById( ‘Errors‘ );
for ( var i
= 0, f; f = files[i]; i++) {
console.log(f.type);
if (!f.type.match(ireg))
{
//设置错误信息
var li
= document.createElement( ‘li‘ );
li.innerHTML
= ‘<li>‘ + f.name
+ ‘不是文本文件.</li>‘ ;
ul.appendChild(li);
continue ;
}
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);
}
} if (window.File && window.FileList
&& window.FileReader && window.Blob) {
document.getElementById( ‘Files‘ ).addEventListener( ‘change‘ ,
fileSelect, false );
} else {
document.write( ‘您的浏览器不支持File
Api‘ );
} |
二、分段读取文件内容(slice)
有的时候,一次性将一个大文件读入内存,并不是一个很好的选择(如果文件太大,使用FileReader读取文件内容,可能直接导致浏览器崩溃),w3c也想到了这种情况,所以html5允许对文件进行分段读取。
chrome以及firefox已经将File slice api调整为如下:
1
2
3
4
5
6
7
|
var blob;
if (file.webkitSlice)
{ //Blob中的方法
blob =
file.webkitSlice(start, end +
1, ‘text/plain;charset=UTF-8‘ );
} else if (file.mozSlice)
{
blob =
file.mozSlice(start, end +
1, ‘text/plain;charset=UTF-8‘ );
} |
本例使用了FileReader的onloadend事件来检测读取成功与否,如果用onloadend则必须检测一下FileReader readyState,因为read abort时也会触发onloadend事件,如果我们采用onload,则可以不用检测readyState。
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
function readBlob(start, end) {
var files
=
document.getElementById( ‘file‘ ).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中的方法
blob
= file.webkitSlice(start, end +
1, ‘text/plain;charset=UTF-8‘ );
} else if (file.mozSlice)
{
blob
= file.mozSlice(start, end +
1, ‘text/plain;charset=UTF-8‘ );
}
reader.readAsBinaryString(blob);
}; try {
document.getElementById( ‘buttons‘ ).addEventListener( ‘click‘ , function (e)
{
if (e.target.tagName.toLowerCase()
== ‘button‘ ) {
var start
=
e.target.getAttribute( ‘data-start‘ ),
end
=
e.target.getAttribute( ‘data-end‘ );
readBlob(start,
end);
}
});
} catch (ex) {
alert( ‘something
error happens!‘ )
} |
NOTE:readAsBinaryString这个方法,读取的二进制字符串,在页面显示,出现中文乱码,不知道怎么解决,如果用reader.readAsText即可正常显示中文;在w3c官网上:binary string, in which every byte is represented by an integer in the range [0..255],而中文却不在[0...255]内,难道是因为这样才出现乱码?
三、FileReader进度条
既然FileReader是异步读取文件内容,那么就应该可以监听它的读取进度。事实上,FileReader的onloadstart以及onprogress等事件,可以用来监听FileReader的读取进度。
在onprogress的事件处理器中,提供了一个ProgressEvent对象,这个事件对象实际上继承了Event对象,提供了三个只读属性:lengthComputable、loaded、total;通过以上几个属性,即可实时显示读取进度。w3c官网上对它的定义如下:
1
2
3
4
5
|
interface ProgressEvent : Event { readonly attribute boolean
lengthComputable;
readonly attribute unsigned long long
loaded;
readonly attribute unsigned long long
total;
}; |
如果处理的文件太大,可能会导致浏览器崩溃(chrome下一般都会崩溃掉,而firefox则不会,不过会触发FileReader的onerror事件,文件读取失败),所以为了安全地、正常地观察到文件读取进度,我们采用分段读取的方法来测试FileReader的进度条。
HTML代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
< form >
< fieldset >
< legend >分度读取文件:</ legend >
< input type = "file" id = "File" />
< input type = "button" value = "中断" id = "Abort" />
< p >
< label >读取进度:</ label >< progress id = "Progress" value = "0" max = "100" ></ progress >
</ p >
< p id = "Status" ></ p >
</ fieldset >
</ form >
|
JS代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
|
var h = {
init: function ()
{
var me
= this ;
document.getElementById( ‘File‘ ).onchange
= me.fileHandler;
document.getElementById( ‘Abort‘ ).onclick
= me.abortHandler;
me.status
=
document.getElementById( ‘Status‘ );
me.progress
=
document.getElementById( ‘Progress‘ );
me.percent
=
document.getElementById( ‘Percent‘ );
me.loaded
= 0;
//每次读取1M
me.step
= 1024 * 1024;
me.times
= 0;
},
fileHandler: function (e)
{
var me
= h;
var file
= me.file = this .files[0];
var reader
= me.reader
= new FileReader();
//
me.total
= file.size;
reader.onloadstart
= me.onLoadStart;
reader.onprogress
= me.onProgress;
reader.onabort
= me.onAbort;
reader.onerror
= me.onerror;
reader.onload
= me.onLoad;
reader.onloadend
= me.onLoadEnd;
//读取第一块
me.readBlob(file,
0);
},
onLoadStart: function ()
{
var me
= h;
},
onProgress: function (e)
{
var me
= h;
me.loaded
+= e.loaded;
//更新进度条
me.progress.value
= (me.loaded / me.total) * 100;
},
onAbort: function ()
{
var me
= h;
},
onError: function ()
{
var me
= h;
},
onLoad: function ()
{
var me
= h;
if (me.loaded
< me.total) {
me.readBlob(me.loaded);
} else {
me.loaded
= me.total;
}
},
onLoadEnd: function ()
{
var me
= h;
},
readBlob: function (start)
{
var me
= h;
var blob,
file
= me.file;
me.times
+= 1;
if (file.webkitSlice)
{
blob
= file.webkitSlice(start, start + me.step + 1);
} else if (file.mozSlice)
{
blob
= file.mozSlice(start, start + me.step + 1);
}
me.reader.readAsText(blob);
},
abortHandler: function ()
{
var me
= h;
if (me.reader)
{
me.reader.abort();
}
}
}; h.init(); |
例子中的进度条采用html5 progress元素来实现的。
每次读取1M的字节(你也可以随便改步长,比如说一次一个字节,然后传一个大小为几字节的文件,也能很好地观察到进度),在一次读取完毕后,onload事件中开启下一次读取,直至整个文件都读取完毕。
如果您的浏览器支持html5,您可以试一下:
这个示例中,没有限制文件大小,读取大文件时,也不会出现浏览器崩溃的情况,可以正常观察到文件的读取进度。
四、参考文章
1、File API3、Blob
HTML5 之 FileReader 的使用 (二) (网页上图片拖拽并且预显示可在这里学到) [转载],布布扣,bubuko.com