本文介绍如何利用 HTML5 新增的 File API 解决 JavaScript 读取本地文件的问题。通过 FileReader 对象和 readAsDataURL 方法,前端可直接读取图片并生成 Base64 字符串进行预览,同时解析单线程异步执行机制与回调函数的应用。
HTML 表单文件上传基础
在 HTML 表单中,实现文件上传功能的唯一控件是 <input type="file">。
需要注意的是,当表单包含 <input type="file"> 时,必须将表单的 enctype 属性设置为 multipart/form-data,并将 method 设置为 post,浏览器才能正确编码并以 multipart/form-data 格式发送数据。
出于安全限制,浏览器仅允许用户通过点击 <input type="file"> 控件选择本地文件,JavaScript 无法直接为该控件的 value 属性赋值。此外,即使用户选择了文件,JavaScript 也无法获取该文件的真实本地路径。
通常,上传的文件由后台服务器处理。JavaScript 可以在提交表单前检查文件扩展名,以拦截无效格式的文件上传。
var f = document.getElementById('test-file-upload');
var filename = f.value; // 'C:\fakepath\test.png'
if (!filename || !(filename.endsWith('.jpg') || filename.endsWith('.png') || filename.endsWith('.gif'))) {
alert('Can only upload image file.');
return false;
}
HTML5 File API 简介
File API
由于早期 JavaScript 对文件的操作能力极为有限,尤其是无法读取文件内容,许多需要处理文件的网页不得不依赖 Flash 等第三方插件。
随着 HTML5 的普及,新增的 File API 允许 JavaScript 直接读取文件内容,从而获取更丰富的文件信息。
HTML5 的 File API 提供了 File 和 FileReader 两个核心对象,用于获取文件信息和读取文件数据。
以下示例演示如何读取用户选取的图片文件,并在一个 <div> 元素中预览图像。
var
fileInput = document.getElementById('test-image-file'),
info = document.getElementById('test-file-info'),
preview = document.getElementById('test-image-preview');
// 监听change事件:
fileInput.addEventListener('change', function () {
// 清除背景图片:
preview.style.backgroundImage = '';
// 检查文件是否选择:
if (!fileInput.value) {
info.innerHTML = '没有选择文件';
return;
}
// 获取File引用:
var file = fileInput.files[0];
// 获取File信息:
info.innerHTML = '文件: ' + file.name + '<br>' +
'大小: ' + file.size + '<br>' +
'修改: ' + file.lastModifiedDate;
if (file.type !== 'image/jpeg' && file.type !== 'image/png' && file.type !== 'image/gif') {
alert('不是有效的图片文件!');
return;
}
// 读取文件:
var reader = new FileReader();
reader.onload = function(e) {
var
data = e.target.result; // 'data:image/jpeg;base64,/9j/4AAQSk...(base64编码)...'
preview.style.backgroundImage = 'url(' + data + ')';
};
// 以DataURL的形式读取文件:
reader.readAsDataURL(file);
});
上述代码展示了如何通过 HTML5 File API 读取文件内容。以 DataURL 形式读取到的文件是一个字符串,格式类似于 data:image/jpeg;base64,/9j/4AAQSk...(base64编码)...,常用于设置图像背景。若需服务器端处理,可将字符串中 base64, 之后的字符发送至服务器,并进行 Base64 解码以还原原始文件的二进制内容。
异步读取与回调机制
回调
上述代码还展示了 JavaScript 的一个重要特性:单线程执行模式。在 JavaScript 中,浏览器的执行引擎始终以单线程模式运行代码,这意味着任何时刻 JavaScript 代码不可能同时拥有超过一个正在执行的线程。你可能会疑惑,采用单线程模式的 JavaScript 如何处理多任务?
在 JavaScript 中,执行多任务实际上都是通过异步调用实现的。例如上面的代码:
reader.readAsDataURL(file);
该操作会发起一个异步任务来读取文件内容。由于是异步操作,JavaScript 代码无法预知操作何时结束,因此需要预先设置一个回调函数。
reader.onload = function(e) {
// 当文件读取完成后,自动调用此函数:
};
当文件读取完成后,JavaScript 引擎会自动调用我们设置的回调函数。在执行回调函数时,文件内容已经读取完毕,因此可以在回调函数内部安全地获取文件内容。