浏览器中无法直接读取文件系统路径,必须通过用户主动选择(如)获取File对象,再用FileReader读取内容;上传需用FormData包裹File对象发送,不可JSON.stringify;多文件、分片、校验等均需前后端协同。

怎么用 File 对象读取本地文件内容
浏览器中无法直接读取文件系统路径,必须通过用户主动选择(如 )触发,才能拿到 File 实例。这个对象是 Blob 的子类,自带 name、size、type 等属性,但内容需用 FileReader 解析。
常见错误是试图直接 console.log(file) 就以为能看见内容——其实只能看到元信息;真正读内容要调用 readAsText()、readAsDataURL() 或 readAsArrayBuffer()。
- 读文本文件(如 .txt、.json):用
readAsText(file, 'UTF-8'),注意编码参数不传可能乱码 - 读图片预览:用
readAsDataURL(file),结果是 base64 字符串,可直接赋给 - 大文件慎用
readAsDataURL,内存暴涨且无法中断;优先考虑分块读取或直接上传
怎么把文件发给后端(不刷新页面)
核心是用 FormData 包裹 File 对象,再通过 fetch 或 XMLHttpRequest 发送。后端收到的是 multipart/form-data,和表单提交行为一致。
关键点在于:不能把 File 直接 JSON.stringify 后发过去——它不是普通 JS 对象,序列化后只剩空对象;也不能手动拼 URL 查询参数上传文件。
立即学习“Java免费学习笔记(深入)”;
-
const fd = new FormData(); fd.append('upload', file);—— 第二个参数必须是File或Blob,不能是路径字符串 - 如果需要额外字段(如用户 ID),用
fd.append('uid', '123'),后端会一并收到 - 用
fetch('/api/upload', { method: 'POST', body: fd })即可;注意不要设Content-Type头,浏览器会自动设置 boundary - 若用
XMLHttpRequest,记得监听upload.onprogress做进度条,fetch原生不支持上传进度
input[type="file"] 的多文件、限制与事件陷阱
默认单选,加 multipile 属性(注意拼写是 multipile 不是 multiple?错,是 multiple)才支持多选;但用户仍可按住 Ctrl/Command 点击多个,或拖拽多个文件到区域——前提是绑定的元素支持 dragover 和 drop 事件。
容易忽略的是:每次选择新文件,input.files 是全新对象,不会和上次合并;清空它不能靠 value = ''(部分浏览器不生效),得用 input.value = null。
- 限制类型:
accept="image/*,.pdf"仅过滤文件选择器界面,不防伪造;服务端必须二次校验file.type和实际二进制头 - 限制大小:前端可用
if (file.size > 5 * 1024 * 1024) {...}提前提示,但不能替代后端校验 -
change事件只在用户选择后触发一次;若想响应拖放,需监听drop并从event.dataTransfer.files取FileList
大文件分片上传为什么不能只靠前端控制
分片本身很简单:用 file.slice(start, end) 得到 Blob,再逐个发给后端。难点在服务端配合——必须能接收分片、暂存、校验顺序、合并,还要处理断点续传(比如记录已上传的 chunk hash)。
前端只做切片和重试逻辑,没服务端支撑就是半截功能。常见错误是认为“前端分了片就等于上传可靠”,结果网络中断后整个流程卡死。
-
file.slice()返回新Blob,不是引用;切片大小建议 1–5 MB,太小 HTTP 开销大,太大内存压力高 - 每个分片应带唯一标识(如文件名 + index + hash),方便后端去重和排序
- 上传完成前,别删掉原始
File对象——万一要重试某一片,还得再 slice 一次 - 移动端对
slice()兼容性没问题,但 iOS Safari 对超大File的size读取偶尔不准,建议用file.arrayBuffer().then(buf => buf.byteLength)校验
文件上传看着简单,真正上线时最常翻车的不是语法,而是对 File 生命周期、HTTP 协议边界、以及前后端职责划分的理解偏差。










