转换文件为Base64格式时如何保留原文件名?React项目实现疑问
根因说明
readAsDataURL返回的Data URL仅包含媒体类型、编码规则和文件内容,本身不携带文件名信息,浏览器识别该类字符串为文件时默认命名为Data属于规范内的预期行为。
原有代码存在两点疏漏:
- 直接将事件对象
e传入readAsDataURL,未从e.target.files中读取原始File实例 - 未手动存储File实例自带的
name属性(即原始文件名)
异常效果如下图:
修复实现
方案1:FileReader读取base64版本
适合需要直接传输base64内容给后端的场景:
const handleGetFiles = (e) => { // 读取选中的所有文件 const selectedFiles = Array.from(e.target.files); selectedFiles.forEach((file, idx) => { const reader = new FileReader(); reader.readAsDataURL(file); reader.onload = () => { fileCollection((prev) => [...prev, { id: Date.now() + idx, // 用时间戳加下标保证唯一ID data: reader.result, fileName: file.name, // 存储原始文件名 fileType: file.type, size: file.size }]); } }) } <Input accept="image/*,video/*" id="contained-button-file" multiple type="file" onChange={handleGetFiles} />
后续使用时直接读取存储的fileName字段即可展示/使用原始文件名,示例渲染逻辑:
fileCollection.map(item => ( <div key={item.id}> <p>{item.fileName}</p> {item.fileType.startsWith('image/') && <img src={item.data} alt={item.fileName} />} </div> ))
方案2:URL.createObjectURL版本
适合前端本地预览场景,性能远高于读取base64:
const handleGetFiles = (e) => { const selectedFiles = Array.from(e.target.files); const newFiles = selectedFiles.map((file, idx) => ({ id: Date.now() + idx, previewUrl: URL.createObjectURL(file), fileName: file.name, rawFile: file // 后续上传可直接使用原始File对象 })) fileCollection(prev => [...prev, ...newFiles]) } // 组件卸载时释放objectURL占用的内存,避免内存泄漏 useEffect(() => { return () => { fileCollection.forEach(item => { if (item.previewUrl) URL.revokeObjectURL(item.previewUrl) }) } }, [])
补充工具方法:base64转标准File对象
如果需要把已存储的base64内容转为带正确文件名的标准File对象用于上传,可使用以下方法:
const dataURLtoFile = (dataUrl, fileName) => { const arr = dataUrl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); let n = bstr.length; const u8arr = new Uint8Array(n); while(n--){ u8arr[n] = bstr.charCodeAt(n); } return new File([u8arr], fileName, {type: mime}); } // 调用示例 const targetFile = dataURLtoFile(storedData, storedFileName)
内容的提问来源于stack exchange,提问作者sbaden
相关产品推荐
相关产品推荐

