轉載至 : 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