File API 只能读取用户主动选择的文件,无法访问任意本地文件;需通过 <input type="file"> 或拖放事件获取 File 对象,用 FileReader 异步读取,注意编码、错误处理与内存优化。

File API 不能“读取任意本地文件”,只能处理用户主动选择的文件——这是安全沙箱的硬性限制,任何绕过它的尝试都会失败。
如何用 <input type="file"> 获取并读取第一个文件
这是最基础、兼容性最好的入口。用户点击输入框选中文件后,change 事件触发,你才能拿到 File 对象。
- 必须校验
e.target.files.length > 0,否则e.target.files[0]是undefined -
FileReader是异步的,reader.result只在onload回调里有效,不要在readAsText()后立刻访问它 - 读文本时建议显式传入编码:
reader.readAsText(file, 'UTF-8'),避免乱码(尤其中文 Windows 文件) - 若文件过大,
readAsText()可能阻塞主线程;超过几 MB 应考虑分块读或改用readAsArrayBuffer()+TextDecoder
示例片段:
const input = document.getElementById('fileInput');
input.addEventListener('change', e => {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = () => {
console.log(reader.result); // ✅ 正确:在 onload 内使用
};
reader.onerror = () => {
console.error('读取失败:', reader.error?.name); // 如 NotReadableError
};
reader.readAsText(file, 'UTF-8');
});
readAsDataURL() 适合图片预览,但要注意内存和尺寸
它把整个文件转成 base64 字符串,赋值给 <img src> 就能立刻显示,无需服务器。
立即学习“前端免费学习笔记(深入)”;
- 图片越大,生成的 data URL 越长,占用大量内存;单张超 5MB 的图可能卡顿或被 Chrome 限制
- 不适用于后续二进制处理(比如 EXIF 解析、压缩),因为 base64 是编码层,不是原始字节
- 若只需预览缩略图,更优解是用
URL.createObjectURL(file)—— 它不加载内容到内存,只生成临时引用 - 用完记得调用
URL.revokeObjectURL()释放引用,否则内存泄漏
拖拽区域读文件时,e.dataTransfer.files 和 input.files 行为一致
拖放(drag & drop)只是另一种触发方式,底层拿到的仍是标准 FileList,可复用同一套读取逻辑。
- 必须拦截
dragenter、dragover的默认行为,否则浏览器会打开文件而不是交给你处理 - 仅支持单文件时,直接取
e.dataTransfer.files[0];多文件需遍历,但注意浏览器对并发FileReader实例数有限制(通常 5–10 个) - 拖入目录?不行。
e.dataTransfer.files不包含子文件,webkitGetAsEntry()已废弃且无跨浏览器支持 - 移动端 Safari 对拖放支持极弱,别依赖它做核心路径
常见错误:误把 FileReader 当同步 API 用
写法 const content = reader.readAsText(file) 是错的 —— 它返回 undefined,不是内容。
-
readAsText()、readAsDataURL()等方法本身不返回数据,只启动异步读取 - 想封装成 Promise?可以,但必须 resolve 在
onload里,reject 在onerror里 - 没写
onerror处理?用户选了损坏文件或权限不足时,页面静默失败,连控制台都不报错(除非你手动检查reader.error) - 多个文件连续读?别复用同一个
FileReader实例,每次都要new FileReader()
真正容易被忽略的点是:File API 不提供文件路径,也不允许你构造 File 对象伪造来源。所有读取都始于用户一次明确的交互动作——点、选、拖。任何试图跳过这一步的方案,要么失效,要么已被现代浏览器封禁。



















