HTML5 File API允许页面使用Javascript来调用和处理本地文件系统的文件。通过HTML5 File API我们可以使用javascript来处理某个文件,例如对文件进行比较,编码,加密,更新等操作。由于涉及到本地文件的操作,HTML5 File API的安全问题也是被人们关注的重点问题。本文将介绍如何使用HTML5 File API,以及HTML5 File API的安全性问题。
HTML5 File API的核心对象
HTML5 File API包含以下的核心对象:
FileList
File
Blob
FileReader
File对象代表本地文件系统中的一个文件。
FileList对象代表本地文件系统中的一组文件。例如在某个目录或文件夹中的所有文件。
Blob对象代表一个二进制大型对象(BLOB),BLOB是本地文件系统中的单个文件的数据。
下面将会接收如何使用这些File API对象。
选择一个文件
在HTML5 File API可以处理本地文件系统中的一个文件之前,用户需要执行一个选择文件的操作。由于安全的原因,通常是通过HTML的元素来选择文件,就像下面的示例代码:
仅仅有input元素是不够的,我们还需要添加一个onchange的事件监听,下面是示例代码:
文件输入域input[type='file']包含一个“浏览”按钮,当用户点击这个按钮的时候,就会弹出一个文件对话框。在这个文件对话框中,用户可以对本地的文件进行选择,被选择的文件将会在onchange事件监听的event对象中作为参数传入。
选择多个文件
要使用户能够选择多个文件,可以在元素中添加一个multiple属性,下面是一个示例代码:
通过拖放选择文件
我们可以将HTML5 file API和HTML5元素拖放相结合来选择文件。这种选择文件的方式需要实现用户从本地电脑的文件系统中(在浏览器之外)拖拽一个文件到浏览器的HTML页面指定的放置区域。HTML页面能通过javascript来检测是否有文件被放置在指定的区域。
下面的代码是如何设置一个放置区域HTML元素,使它能够检测到是否有文件放置到它上面。
请拖拽文件到这里
function drop(event) {
evt.stopPropagation();
evt.preventDefault();
var fileList = event.dataTransfer.files;
// 通过fileList接收文件
}
function dragOver(evt) {
evt.stopPropagation();
evt.preventDefault();
evt.dataTransfer.dropEffect = 'copy';
}
var dropZone = document.getElementById("fileDropZone");
dropZone.addEventListener("dragover", dragOver, false);
dropZone.addEventListener("drop" , drop , false);
dragOver()和drop()函数设置放置区域HTML元素的拖和放事件监听。
当一个文件被放置在放置区域的时候,drop()函数将被调用。被放置在放置区域的文件列表可以通过event.dataTransfer.files对象(一个FileList对象)来找到。
dragOver()函数是可选的。它仅用于文件被拖拽时的一个副本。它通过一个文件图标来显示。
剩下的代码是访问选择的文件,它和通过input元素来选择一个文件后的操作是相同的。
在实际操作中最好为放置区域HTML元素设置一些样式,使用户能够明确的指定这里是可以拖拽放置的区域。
访问被选择的文件
当用户选择一个或多个文件之后,有两种方式访问这些被选择的文件。
第一种访问被选择文件的方式是访问input元素的files属性。下面是一个示例代码:
var inputField = document.getElementById('theFileInput');
var selectedFiles = inputField.files;
for(var i=0; i
var file = selectedFiles[i);
}
第二种访问被选择文件的方式是通过input元素的onchange事件监听。被选择的文件会作为event对象的参数被传入。下面是一个示例代码:
function readFiles(event) {
var fileList = event.target.files;
}
event.target.files对象是一个FileList对象。它包含一组被选择的文件(File对象)。如果只有一个文件被选择,这个列表中就只有一个对象。下面的实例代码说明了如何去迭代一组文件列表。
function readFiles(event) {
var fileList = event.target.files;
for(var i=0; i < fileList.length; i++ ) {
var file = fileList[i]; // a File object
console.log("i: " + i + " - " + file.name);
}
}
FileList是一组File对象列表。File对象用于访问文件。在下面的介绍中,你会看到通过javascript来加载文件的不同方法。
通过FileReader来加载文件
当用户选择了一个文件后。我们得到了一个文件的引用(例如通过onchange事件)。我们可以通过FileReader来读取这个文件。FileReader对象有下面的一些方法可以用于读取文件:
readAsText()
readAsDataUrl()
readAsArrayBuffer()
上面的方法都使用一个File对象或Blob对象作为参数。
File对象可以从FileList对象中获取,前面已经介绍过。
Blob对象代表部分或整个文件。你可以从File对象中创建一个Blob对象,下面是示例代码:
var theFile = fileList[0]; // 从FileList获取一个File对象
var from = 3;
var to = 9;
var blob = theFile.slice(from, to); // 创建Blob对象
上面的代码用slice方法来分割一个文件,Blob对象从文件的第3个字节开始,到第8个字节结束(不包含第9个字节)。
创建一个FileReader
要使用FileReader你先要创建FileReader对象。创建FileReader对象的方法如下:
var reader = new FileReader();
当FileReader对象被创建之后,你就可以使用它来读取文件了。
将一个文件作为文本来加载
要将一个文件作为文本来加载,你可以使用HTML5 file API的FileReader对象。下面是一个示例代码:
function readFiles(event) {
var fileList = event.target.files;
for(var i=0; i < fileList.length; i++ ) {
loadAsText(fileList[i]);
}
}
function loadAsText(theFile) {
var reader = new FileReader();
reader.onload = function(loadedEvent) {
// 返回包含被加载的文件
console.log(loadedEvent.target.result);
}
reader.readAsText(theFile);
}
文件在loadAsText()函数中被加载。
上面的代码首先创建了一个FileReader对象,然后在FileReader对象上调用onload事件,这个事件在文件被加载完毕之后被调用。
接着,FileReader中的readAsText()函数被调用,它使用一个File对象作为参数。这里是加载文件的开始,当文件加载完毕,onload事件将被调用。
加载部分文件
你可以只加载一个文件的某一部分,而不是整个文件。下面的loadAsTextSlice()函数展示了如何使用HTML5 file API来加载文件的一部分内容。
function loadAsTextSlice(theFile) {
var start = 3;
var stop = 9;
var blob = theFile.slice(start, stop);
var reader = new FileReader();
reader.onload = function(loadedEvent) {
console.log(loadedEvent.target.result);
}
reader.readAsText(blob);
}
上面的例子通过File对象的slice()方法创建了一个Blob对象。然后创建一个FileReader对象,然后在它上面添加onload()事件监听。
接下来FileReader对象的readAsText()被调用,它的参数是一个Bolb对象。这是读取文件的开始,当这部分文件被读取完毕,onload()方法就会被调用。要获取这部分被读取的文件,可以通过loadedEvent.target.result来获取。
通过Data URL来加载文件
我们还可以通过data URL来加载一个文件。典型的例子是一个图片的数据,我们可以读取图片的数据,然后将这些数据设置到图片的src属性中。下面的loadAsUrl()函数展示了如何使用HTML5 file API将文件作为data URL进行读取。
function loadAsUrl(theFile) {
var reader = new FileReader();
reader.onload = function(loadedEvent) {
var image = document.getElementById("theImage");
image.setAttribute("src", loadedEvent.target.result);
}
reader.readAsDataURL(theFile);
}
上面的代码中首先创建了一个FileReader对象,然后在这个FileReader对象上设置onload()事件监听。当文件加载完毕,onload()事件就会被触发。onload()函数的参数是loadedEvent,通过这个参数,我们可以获取被编码为data URL的文件数据,使用的是event.target.result属性。在获取了编码的文件数据之后,我们就可以把这些数据设置为图片src属性的值,这样图片就会被显示出来。
通过ArrayBuffer来加载文件
FileReader对象的readAsArrayBuffer()函数可以用于作为ArrayBuffer来读取文件数据。一个ArrayBuffer代表任意长度的缓冲区数据。你不能够直接在ArrayBuffer中操作数据,你必须创建一个DataView对象,该对象可以接收任意类型的ArrayBuffer数据。
下面是一个例子:
function loadAsUrl(theFile) {
var reader = new FileReader();
reader.onload = function(loadedEvent) {
var arrayBuffer = loadedEvent.target.result;
var dataView = new DataView(arrayBuffer, 0, arrayBuffer.byteLength);
var byte = dataView.getUint8(0); //获取ArrayBuffer的第一个字节
//... 处理余下的dataView ...
}
reader.readAsArrayBuffer(theFile);
}
关于DataView对象的更多资料,可以参考这里。
跟踪文件加载的进程
HTML5 file API允许我们跟踪文件加载的进程,这意味着我们可以知道当前文件加载了多少。要跟踪文件加载的进程,可以在FileReader对象上添加onprogress事件监听。
var reader = new FileReader();
reader.onprogress = function(progressEvent) {
if(progressEvent.lengthComputable) {
var percentLoaded = Math.round( (
progressEvent.loaded * 100) / progressEvent.total );
}
console.log("total: " + progressEvent.total + ", loaded: "
+ progressEvent.loaded + "(" + percentLoaded + "%)");
}
传入到onprogress事件中的progressEvent参数包含一个布尔值的属性lengthComputable。如果这个属性的值为true,你就可以计算文件已经被加载了多少,具体操作就像上面代码的样子。
浏览器对HTML5 File API的支持
浏览器对HTML5 File API的支持可以通过caniuse.com来查看。IE8和IE9不支持它,其它的现代浏览器都支持HTML5 File API。但是有一些浏览器不支持File对象的构造函数,这其实对使用没有什么影响。