文件操作
文件操作简介
在 HTML5 中,文件上传是使用 input 元素来实现的,其中 type 属性取值为 “file”。
<input type="file" />
文件上传 input 元素有两个重要属性:multiple 和 accept。multiple 属性表示“是否选择多个文件”。其中,下面两句代码是等价的:
<input type="file" multiple />
<input type="file" multiple="multiple" />
accept 属性用于设置文件的过滤类型(MIME类型),常见的 accept 属性取值如表:
如果想要同时设置多个过滤类型,可以使用英文逗号(,)隔开,例如:
<input type="file" accept="image/jpeg, image/png"/>
举例:选择单个文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<form method="post">
<input type="file" />
</form>
</body>
</html>
举例:选择多个文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<form method="post">
<input type="file" multiple/>
</form>
</body>
</html>
为元素添加 multiple 属性后,就可以选择多个文件了。当选择成功后,按钮右侧不再显示文件的名称,而是显示文件的总量。当将鼠标指针移到上面时,就会显示全部上传文件的详细列表,
举例:accept 属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<form method="post">
<input type="file" accept="image/png" multiple/>
</form>
</body>
</html>
accept="image/png"
表示只可以上传后缀名为 .png
格式的文件(也就是 PNG
图片),如果选择其他文件,则是无法上传的。
默认的 <input type="file" />
元素比较难看,在实际开发中,为了获得更好的用户体验,我们一般都是使用 “opacity: 0;” 来隐藏原来的表单元素,然后在上面覆盖一个美化的按钮或者提示语。
举例:file 类型元素的样式美化
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
/*去除默认样式*/
* {
margin: 0;
padding: 0;
}
.container {
width: 160px;
margin: 30px auto;
}
.filePicker {
position: relative;
width: 160px;
height: 44px;
line-height: 44px;
text-align: center;
color: #ffffff;
background: #00b7ee;
}
.filePicker input[type="file"] {
position: absolute;
top: 0;
left: 0;
width: 160px;
height: 44px;
opacity: 0;
cursor: pointer;
}
</style>
</head>
<body>
<!--默认时的表单-->
<div class="container">
<input type="file" />
</div>
<!--美化后的表单-->
<div class="container">
<div class="filePicker">
<label>点击选择文件</label>
<input id="fileInput" type="file" accept="image/*" multiple />
</div>
</div>
</body>
</html>
分析:
想要对 file 类型元素进行美化,我们都是这样处理的:首先使用 opacity: 0;
将表单设置为透明,然后使用绝对定位在表单原来的位置上面定义一个 label 就可以了。
这里还要说明一下,使用了 opacity:0;
之后,虽然表单看不见了,但它并没有消失,还占据着原来的位置,因此,我们点击原来的位置,还可以继续使用表单的功能。这个地方非常巧妙,也是实现的关键。
File 对象
在文件上传元素中,将会产生一个 FileList 对象,它是一个类数组对象,表示所有文件的集合。其中,每一个文件就是一个 File 对象。
想要获取某一个文件对象(即 File 对象),我们首先需要获取 FileList 对象,然后再通过数组下标形式来获取。
File 对象的属性
举例:File 对象的属性
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
window.onload = function () {
//获取FileList对象
var oFile = document.getElementById("file");
oFile.onchange = function () {
//获取第1个文件,即File对象
var file = oFile.files[0];
console.log("图片名称为:" + file.name);
console.log("图片大小为:" + file.size + "B");
console.log("图片类型为:" + file.type);
console.log("修改时间为:" + file.lastModifiedDate);
};
};
</script>
</head>
<body>
<input id="file" type="file" accept="image/*" multiple />
</body>
</html>
当我们点击【选择文件】按钮,选择一张本地图片后,此时在浏览器控制台中会输出图片的名称、大小、类型以及修改时间,
由于 file.size
获取到的大小值的单位是 B(字节),在实际开发中,我们大多数情况下都会将 file.size
换算为常见的文件大小单位,请看下面的例子:
<!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];
//将单位“B”转化为“KB”
var size = file.size / 1024;
var unitArr = ["KB", "MB", "GB", "TB"];
//转化单位
for (var i = 0; size > 1; i++) {
var fileSizeString = size.toFixed(2) + unitArr[i];
size /= 1024;
}
//输出结果
console.log("图片大小为:" + fileSizeString);
};
};
</script>
</head>
<body>
<input id="file" type="file" accept="image/*" />
</body>
</html>
FileReader 对象
在 HTML5 中,专门提供了一个文件操作的 API,即 FileReader 对象。我们通过 FileReader 对象可以很方便地读取文件中的数据。
FileReader 对象有 5 个方法,其中 4 个用来读取文件数据,另外 1 个用于中断读取操作
FileReader 对象的方法
readAsText() 方法有两个参数:第 1 个参数为 File 对象,第 2 个参数为文本的编码方式,默认值为 “utf-8”。这个方法非常容易理解,表示将文件以文本方式读取,读取的结果就是这个文本文件的内容。
readAsBinaryString() 方法将文件读取为二进制字符串,通常我们将它传送到后端,后端可以通过这段字符串来存储文件。
abort() 方法可以用来中止读取操作,在读取大文件时,这个方法非常有用。
FileReader 对象提供了6个事件,用于检测文件的读取状态,如表:
FileReader 对象的事件
var reader = new FileReader();
reader.readAsText(file, 编码);
reader.onload = function(){
//成功读取后的操作
};
举例:读取TXT文本(readAsText()方法)
<!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];
//读取本地文件,以GBK编码方式输出
var reader = new FileReader();
reader.readAsText(file, "gbk");
reader.onload = function () {
console.log(this.result);
};
};
};
</script>
</head>
<body>
<input id="file" type="file" />
</body>
</html>
reader.onload = function(){
this.result;
};
对于上面这段代码,一旦开始读取文件,无论成功或失败,实例的 result 属性(即 this.result)都会被填充。如果读取成功,则 this.result 的值就是当前文件的内容;如果读取失败,则 this.result 的值为 null。
举例:在线预览图片(readAsDataURL()方法)
<!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>
我们都知道,“img 元素的 src 属性”或者“其他元素的 background 属性的 url”,都可以被赋值为 Base64 编码,然后显示图片。在 HTML5 以前,我们一般都是先将本地图片上传到服务器,等上传成功后再由后台返回图片的地址在前端显示。到了 HTML5 时代,我们使用 FileReader 对象的 readAsDataURL() 方法,可以不经过后台而直接将本地图片显示在页面中,这样可以减少前后端的频繁交互,减少服务器端的压力。
举例:拖曳文件并读取
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box {
width: 150px;
height: 150px;
border: 1px solid silver;
}
</style>
<script>
window.onload = function () {
var oBox = document.getElementById("box");
var oContent = document.getElementById("content");
//阻止默认行为
oBox.ondragover = function (e) {
e.preventDefault();
};
//添加ondrop事件
oBox.ondrop = function (e) {
e.preventDefault();
//读取文本
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsText(file, "gbk");
reader.onload = function () {
//把文本内容添加到页面
oContent.innerHTML = this.result;
};
};
};
</script>
</head>
<body>
<div id="box"></div>
<p id="content"></p>
</body>
</html>
当我们拖动本地的一个 TXT 文件到页面的框中时,就会读取 TXT 文件中的内容,并且添加到页面中,
举例:拖曳图片并预览
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style type="text/css">
#box {
width: 150px;
height: 150px;
border: 1px solid silver;
}
</style>
<script>
window.onload = function () {
var oBox = document.getElementById("box");
var oContent = document.getElementById("content");
//阻止默认行为
oBox.ondragover = function (e) {
e.preventDefault();
};
//添加ondrop事件
oBox.ondrop = function (e) {
e.preventDefault();
//获取File对象
var file = e.dataTransfer.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
var oImg = document.createElement("img");
//设置图片src为this.result
oImg.src = this.result;
oImg.style.width = "150px";
oImg.style.height = "150px";
oBox.appendChild(oImg);
};
};
};
</script>
</head>
<body>
<div id="box"></div>
</body>
</html>
当我们拖动本地的一个图片到页面的框中时,就会把图片添加到页面中。
Blob 对象
在 HTML5 中,还新增了一个 Blob 对象,用于代表原始二进制数据。实际上,前面介绍的 File 对象也继承于 Blob 对象。
var blob = new Blob(dataArray, type);
Blob() 构造函数有两个参数,这两个参数都是可选参数,而并非必选参数。
第1个参数 dataArray 是一个数组,数组中的元素可以是以下类型的对象:
- String对象(即字符串)
- Blob对象(即其他Blob对象)
- ArrayBuffer对象
- ArrayBufferView对象
第 2 个参数 type 是一个字符串,表示 Blob 对象的 MIME 类型。
举例:创建并下载TXT文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
window.onload = function () {
var oTxt = document.getElementById("txt");
var oBtn = document.getElementById("btn");
var oDiv = document.getElementById("container");
oBtn.onclick = function () {
var text = oTxt.value;
var blob = new Blob([text], { type: "text/plain" });
//通过createObjectURL()方法创建文字链接
oDiv.innerHTML =
'<a download href="' +
window.URL.createObjectURL(blob) +
'" target="_blank">下载文件</a>';
};
};
</script>
</head>
<body>
<textarea id="txt" cols="30" rows="10"></textarea><br />
<input id="btn" type="button" value="创建链接" />
<div id="container"></div>
</body>
</html>
Blob 对象可以通过 window.URL 对象的 createObjectURL()
方法生成一个网络地址,然后结合 a 标签的 download 属性来实现下载文件的功能。
如果想要创建及下载 HTML 文件,只需要把 var blob = new Blob([text],{type:"text/plain"});
改为 var blob = new Blob([text],{type: "text/html"});
就可以了。
此外,想要重命名文件,可以使用 a 元素的 download 属性。
上面这个例子需要额外创建一个文本链接,然后点击该文本链接才会实现下载文件的功能。如果我们不希望创建多余的元素,而是直接点击按钮就能实现下载,此时又该怎么实现呢?
举例:改进版(无须添加多余元素)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script>
window.onload = function () {
var oTxt = document.getElementById("txt");
var oBtn = document.getElementById("btn");
var oDiv = document.getElementById("container");
oBtn.onclick = function () {
//Blob中数据为“文字”,默认编码为“utf-8”
var text = oTxt.value;
var blob = new Blob([text], { type: "text/plain" });
//通过createObjectURL()方法创建文字链接
var oA = document.createElement("a");
var url = window.URL.createObjectURL(blob);
oA.download = "download";
oA.href = url;
//添加元素
document.body.appendChild(oA);
//触发点击
oA.click();
//移除元素
document.body.removeChild(oA);
};
};
</script>
</head>
<body>
<textarea id="txt" cols="30" rows="10"></textarea><br />
<input id="btn" type="button" value="下载文件" />
</body>
</html>
实际上,除了 TXT 文件,像 HTML 文件、JSON 文件等,也可以利用这种小技巧来实现文件下载操作。
举例:将 Canvas 下载为一个图片文件
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
function $$(id) {
return document.getElementById(id);
}
window.onload = function () {
var cnv = $$("canvas");
var cxt = cnv.getContext("2d");
//定义文字
var text = "绿叶学习网";
cxt.font = "bold 60px 微软雅黑";
//定义阴影
cxt.shadowOffsetX = 5;
cxt.shadowOffsetY = 5;
cxt.shadowColor = "#66CCFF";
cxt.shadowBlur = 10;
//填充文字
cxt.fillStyle = "#FF6699";
cxt.fillText(text, 10, 90);
//点击按钮,下载图片
$$("btn").onclick = function () {
cnv.toBlob(
function (blob) {
//通过createObjectURL()方法创建文字链接
var oA = document.createElement("a");
var url = window.URL.createObjectURL(blob);
//此处设置图片名称
oA.download = "download";
oA.href = url;
//添加元素
document.body.appendChild(oA);
//触发点击
oA.click();
//移除元素
document.body.removeChild(oA);
},
"image/jpeg",
1
);
};
};
</script>
</head>
<body>
<canvas
id="canvas"
width="320"
height="150"
style="border: 1px solid silver"
></canvas
><br />
<input id="btn" type="button" value="下载图片" />
</body>
</html>
我们可以使用 Canvas 对象的 toBlob() 方法来创建一个 Blob 对象。其中,toBlob() 方法有3个参数:
- 第1个参数是一个回调函数;
- 第2个参数是图片类型(默认值为image/png);
- 第3个参数是图片质量(取值为0~1),
语法格式如下:
cnv.toBlob(function(blob){
//...
}, "image/jpeg", 0.5);
在实际开发中,FileReader 对象的 readAsText()、readAsArrayBuffer() 等方法可以读取文件数据,然后结合 Blob 对象下载文件的功能,就可以实现将数据导出文件备份到本地。当要恢复数据时,通过 input 元素上传备份文件,使用 readAsText()、readAsArrayBuffer() 等方法读取文件,即可恢复数据。