一、FileReader介绍
HTML5定义了FileReader作为文件API的重要成员用于读取文件,根据W3C的定义,FileReader接口提供了读取文件的方法和包含读取结果的事件模型。
FileReader的使用方式非常简单,可以按照如下步骤创建FileReader对象并调用其方法:
1.检测浏览器对FileReader的支持
if(window.FileReader) {
var fr = new FileReader();
// add your code here
}
else {
alert("Not supported by your browser!");
}
//判断浏览器是否支持FileReader
if (typeof FileReader == "undefined") {
document.write("您的浏览器不支持FileReader");
} else {
document.write("您的浏览器支持FileReader");
}
FileReader是一种异步文件读取机制,结合input:file可以很方便的读取本地文件。
input:file
在介绍FileReader之前,先简单介绍input的file类型。
<input type="file" id="file">
input的file类型会渲染为一个按钮和一段文字。点击按钮可打开文件选择窗口,文字表示对文件的描述(大部分情况下为文件名);file类型的input会有files属性,保存着文件的相关信息。
document.querySelector('#file').addEventListener('change',(fileChoosed) => {
console.log('fileChoosed', fileChoosed.target.files)
})
点击按钮上传一个文件后,在控制台打印上传的文件信息,如下:
可以发现文件信息是一个json对象,由传入的file对象组成。每个file对象(即每个上传文件)包含以下属性:
lastModified:数值,表示最近一次修改时间的毫秒数;
lastModifiedDate:对象,表示最近一次修改时间的Date对象;
name:本地文件系统中的文件名;
size:文件的字节大小;
type:字符串,文件的MIME类型;
webkitRelativePath:此处为空;当在input上加上webkitdirectory属性时,用户可选择文件夹,此时webkitRelativePath表示文件夹中文件的相对路径。
<input type="file" id="file" webkitdirectory>
二、FileReader简单使用
FileReader 的实例拥有 4 个方法,其中 3 个用以读取文件,另一个用来中断读取。下面的表格列出了这些方法以及他们的参数和功能,需要注意的是 ,无论读取成功或失败,方法并不会返回读取结果,这一结果存储在 result属性中。
以上file对象只获取到了对文件的描述信息,但没有获得文件中的数据。我们可以通过html5提供的FileReader读取到文件中的数据。
首先创建一个FileReader实例:
const reader = new FileReader();
FileReader提供了如下方法:
readAsArrayBuffer(file)
按字节读取文件内容,结果用ArrayBuffer对象表示
readAsBinaryString(file)
按字节读取文件内容,结果为文件的二进制串
readAsDataURL(file)
读取文件内容,结果用data:url的字符串形式表示
readAsText(file,encoding)
按字符读取文件内容,结果用字符串形式表示
abort()
终止文件读取操作
readAsDataURL和readAsText较为常用,这里只对这两者进行说明。
readAsDataURL会将文件内容进行base64编码后输出:
document.querySelector('#file').addEventListener('change',(fileChoosed) => {
const reader = new FileReader();
reader.readAsDataURL(fileChoosed.target.files[0]);//发起异步请求
reader.onload = function(readRes){
console.log('加载完成', readRes.target.result)
}
})
控制台为当前所传文件的base64编码表示。由于媒体文件的src属性,可以通过采用网络地址或base64的方式显示,因此我们可以利用readAsDataURL实现对图片的预览。
如下,只需将读取的结果赋给图片的src属性,即可预览图片:
<input type="file" id="file" />
<img src="" id="imgPreview">
document.querySelector('#file').addEventListener('change',(fileChoosed) => {
const reader = new FileReader();
reader.readAsDataURL(fileChoosed.target.files[0]);//发起异步请求
reader.onload = function(readRes){
document.querySelector('#imgPreview').src = readRes.target.result
}
})
readAsText可按指定编码方式读取文件,但读取文件的单位是字符,故对于文本文件,只要按规定的编码方式读取即可;而对于媒体文件(图片、音频、视频),其内部组成并不是按字符排列,故采用readAsText读取,会产生乱码。
FileReader事件:
FileReader 包含了一套完整的事件模型,用于捕获读取文件时的状态,下面这个表格归纳了这些事件。
onloadstart 当读取操作开始时调用
onprogress 在读取数据过程中周期性调用
onabort 当读取操作被中止时调用
onerror 当读取操作发生错误时调用
onload 当读取操作成功完成时调用
onloadend 当读取操作完成时调用,无论成功,失败或取消
注释:
每过50ms左右,就会触发一次progress事件,对于较大的文件可以利用progress实现进度条;
由于种种原因无法读取文件时,会触发error事件。触发error事件时,相关信息保存在FileReader对象的error属性中,这个属性将保存一个对象,此对象只有一个属性code,即错误码。1表示未找到文件,2表示安全性错误,3表示读取中断,4表示文件不可读,5表示编码错误。
示例:
<input type="file" id="file" />
document.querySelector('#file').addEventListener('change',(fileChoosed) => {
const reader = new FileReader();
reader.readAsText(fileChoosed.target.files[0],'utf-8');//发起异步请求
reader.onloadstart = function(readRes){
// 文件大于500kb则取消加载
if(readRes.total > 1024*500) {
reader.abort()
} else {
console.log("开始加载")
}
}
reader.onabort = function (readRes) {
console.log('加载已取消')
}
reader.onprogress = function(readRes){
console.log("加载中", `${(readRes.loaded / readRes.total).toFixed(2)*100}/100`)
}
reader.onload = function(readRes){
console.log('加载成功')
}
reader.onloadend= function(readRes){
console.log("加载结束")
}
})
文件一旦开始读取,无论成功或失败,实例的 result 属性都会被填充。如果读取失败,则 result 的值为 null ,否则即是读取的结果,绝大多数的程序都会在成功读取文件的时候,抓取这个值。
fr.onload = function() {
this.result;
};
下面是部分实例代码:
h5使用FileReader读取本地图片文件并显示到浏览器
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>h5使用FileReader读取本地图片文件并显示到浏览器-赵克立博客</title>
<meta name="keywords" content="h5使用FileReader读取本地图片文件并显示到浏览器-赵克立博客" />
<meta name="description" content="h5使用FileReader读取本地图片文件并显示到浏览器-赵克立博客" />
</head>
<body>
<input type="file" id="file_input" name="img" />
<div id="showimg">
</div>
<script type="text/javascript">
! function(a, b) {
var showimg = document.getElementById("showimg");
var imginput = document.getElementById("file_input");
if (typeof FileReader === 'undefined') {
showimg.innerHTML = "抱歉,你的浏览器不支持 FileReader";
imginput.setAttribute('disabled', 'disabled');
} else {
imginput.addEventListener('change', function() {
var file = this.files[0];
if (!/image\/\w+/.test(file.type)) {
alert("请确保文件为图像类型");
return false;
}
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e) {
showimg.innerHTML = '<img src="' + this.result + '" alt=""/>'
}
}, false);
}
}(window);
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title></title>
<script>
window.onload = function () {
var oFile = document.getElementById("file");
oFile.onchange = function(){
//获取第1个文件
var file = oFile.files[0];
//将图片转换为Base64格式
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(){
//添加图片到页面中
var oImg = document.createElement("img");
oImg.src = this.result;
document.body.appendChild(oImg);
};
};
}
</script>
</head>
<body>
<input id="file" type="file" /><br/>
</body>
</html>
读取本地文本文件并显示.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>读取本地文件文件并显示</title>
</head>
<body>
<script>
function show()
{
var reader = new FileReader();
reader.onload = function()
{
//alert(this.result)
story.value=this.result
}
var f = document.getElementById("filePicker").files[0];
reader.readAsText(f);
}
</script>
<input type="file" name="file" id="filePicker" onchange="show()" />
<br>
<textarea id="story" name="story" rows="15" cols="60">
</textarea>
</body>
</html>
读取本地图片文件并显示.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>读取本地图片文件并显示</title>
</head>
<body>
<!-- multiple 一个文件选择框可以同时选择多个文件
<input type="file" id="selectFiles" onchange="dealSelectFiles()" multiple webkitdirectory>
-->
<input type="file" id="selectFiles" onchange="dealSelectFiles()" >
<canvas id="myCanvas" width=1440 height=900></canvas>
<script>
var imgPosX = 0;
var imgWidth = 256;
function dealSelectFiles(){
// get select files.
var selectFiles = document.getElementById("selectFiles").files;
for(var file of selectFiles){
console.log(file.webkitRelativePath);
// read file content.
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = function(){
// deal data.
var img = new Image();
// after loader, result storage the file content result.
img.src = this.result;
img.onload = function(){
var myCanvas = document.getElementById("myCanvas");
var cxt = myCanvas.getContext('2d');
cxt.drawImage(img, imgPosX, 0);
imgPosX += imgWidth;
}
}
}
}
</script>
</body>
</html>
拖拽
拖拽是另一种常见的文件访问场景,这种方式通过dataTransfer的对象来获得拖拽文件列表。同样可以支持多文件拖拽。
下面给出拖拽本地文本文件并在textarea中显示的源码:
拖拽本地文本文件并显示例.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>拖拽本地文本文件并显示</title>
<style>
.box {
width: 400px;
height: 400px;
border: 1px solid #000;
margin: 100px auto;
box-shadow: 0 0 10px 5px rgba(0,0,0,.8);
border-radius: 10px;
line-height: 400px;
text-align: center;
font-size: 30px;
font-weight: 700;
text-shadow:0 0 5px;
transition:all 1s;
}
.box #entity{
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div class="box">拖拽外部文件至此</div>
<script>
// 需求:拖拽外部文件到当前页面进行解析
// 获取目标元素
var box = document.querySelector('.box');
//解决一旦拖拽外部文件就覆盖掉当前页面的问题
// 解决:给document绑定drop事件
// drop事件默认触发不了,需要在dragover事件里面阻止默认事件
document.ondrop = function(e){
e.preventDefault();
}
// 这个阻止默认事件是为了让drop事件得以触发
document.ondragover = function(e){
e.preventDefault();
}
box.ondragenter = function(){
box.style.boxShadow = '0 0 10px 5px rgba(255,0,0,.8)';
}
box.ondrop = function(e){
// console.log(e);
// 得到拖拽过来的文件
var dataFile = e.dataTransfer.files[0];
// FileReader实例化
var fr = new FileReader();
// 异步读取文件
fr.readAsText(dataFile);
// 读取完毕之后执行
fr.onload = function(){
// 获取得到的结果
var data = fr.result;
var ta = document.createElement('textarea');
ta.value = data;
ta.id='entity';
box.innerHTML = '';
box.appendChild(ta);
}
}
</script>
</body>
</html>
拖拽本地图片文件并显示.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>拖拽本地图片文件并显示</title>
<style type="text/css">
#area{width:100%;height:200px; line-height: 200px; text-align: center; border: 1px solid #DDDDDD;}
#prev{width:100%;min-height: 400px; border: 1px solid #FF0000;}
</style>
</head>
<body>
<div id="area">将图片拖放到该区域</div>
<h1>图片预览</h1>
<hr />
<div id="prev"></div>
</body>
<script>
window.onload = function(){
var oArea = document.getElementById("area");
var oPrev = document.getElementById("prev");
oArea.ondragenter = function(){
oArea.innerHTML = "请释放鼠标";
}
oArea.ondragleave = function(){
oArea.innerHTML = "将图片拖放到该区域";
}
oArea.ondragover = function(ev){
ev.preventDefault();
}
oArea.ondrop = function(ev){
ev.preventDefault();
var files = ev.dataTransfer.files;
for(var i = 0 , len = files.length;i<len;i++){
var file = files[i];
var reader = new FileReader();
reader.readAsDataURL(file);
(function(reader){
reader.onload = function(){
var oImg = document.createElement("img");
oImg.src = this.result;
oPrev.appendChild(oImg);
}
})(reader);
}
}
}
</script>
</html>