转载至 : http://www.360doc.com/content/14/0214/18/1457948_352511645.shtmlcss
FileReader 资料(英文): https://developer.mozilla.org/en-US/docs/Web/API/FileReader#State_constantshtml
前面本博介绍了File API,这里将继续介绍一下FileReader,用FileReader具体地读取文件内容。html5
File API一文中主要介绍获取文件句柄的方法,接下来咱们就要利用该文件句柄来读取文件内容,这是经过FileReader来实现的,经过FileReader接口,咱们能够异步地将文件内容加载到内存中,赋予某个js变量。web
FileReader具体支持哪些方法和事件,这里就不介绍了,有兴趣的能够去w3c官网上看看FileReader介绍,这里主要介绍一下FileReader两个常见应用。chrome
这里主要用到FileReader的readAsDataURL方法,经过将图片数据读取成Data URL的方法,将图片展现出来,关于DATA URI。api
示例脚本:浏览器
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样式,主要是为了让浏览器对图片进行等比缩放处理,因此在浏览器中展现出来的图片并非原始大小的图片,而是通过浏览器自动等比缩放的图片;若是须要查看原始尺寸图片,可点击相应图片;再次单击该图片,则恢复小图片。服务器
这里主要用到FileReader的readAsText,对于诸如mimetype为text/plain、text/html等文件均认为是文本文件,即minetype为text开头都能在本例中预览。cookie
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'
);
}
|
有的时候,一次性将一个大文件读入内存,并非一个很好的选择(若是文件太大,使用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的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,您能够试一下:
这个示例中,没有限制文件大小,读取大文件时,也不会出现浏览器崩溃的状况,能够正常观察到文件的读取进度。
一、 File API二、 FileReader三、 Blob