JavaScript如何完整复制File对象保留全部属性仅修改文件名
为上传图片生成带后缀预览图时保留原文件全部属性的方案
需求说明
- 为待上传的图片生成体积更小的预览图
- 预览图文件名需要在原文件名末尾追加
_preview后缀
原有实现代码
uploadFile.map((file) => { if (file.type.includes('image')) { console.log('Generating thumbnail for ' + file.name) const fileName = file.name.split('.').slice(0, -1).join('.') const fileExtension = file.name.split('.').pop() const compressedFile = new File( [file.slice(0, file.size, file.type)], fileName + '_preview.' + fileExtension, ) console.log('Generated file:', compressedFile) convert({ file: compressedFile, width: 300, height: 300, type: fileExtension, }) .then((resp) => { uploadFile.push(resp) }) .catch((error) => { // Error console.error('Error compressing ', file.name, '-', error) }) } })
问题原因
创建File实例时没有传入第三个配置参数,导致原文件的MIME类型(type字段)丢失;webkitRelativePath属于File实例的只读属性,不会自动从原文件继承,最终触发convert函数的File type not supported报错。
修复方法
- 创建新File实例时,显式传入第三个配置对象,把原文件的
type、lastModified等可配置属性带上 - 对于
webkitRelativePath这类构造函数不支持直接传入的只读属性,创建实例后通过Object.defineProperty手动赋值
修复后的核心代码
uploadFile.map((file) => { if (file.type.includes('image')) { console.log('Generating thumbnail for ' + file.name) const fileName = file.name.split('.').slice(0, -1).join('.') const fileExtension = file.name.split('.').pop() // 创建新File时传入配置保留基础属性 const compressedFile = new File( [file], `${fileName}_preview.${fileExtension}`, { type: file.type, lastModified: file.lastModified } ) // 手动补充webkitRelativePath只读属性 if (file.webkitRelativePath) { Object.defineProperty(compressedFile, 'webkitRelativePath', { value: file.webkitRelativePath, writable: false, configurable: true }) } console.log('Generated file:', compressedFile) convert({ file: compressedFile, width: 300, height: 300, type: fileExtension, }) .then((resp) => { uploadFile.push(resp) }) .catch((error) => { console.error('Error compressing ', file.name, '-', error) }) } })
注:原代码中
file.slice(0, file.size, file.type)属于冗余操作,File本身是Blob的子类,可以直接作为内容参数传入新的File构造函数。
内容的提问来源于stack exchange,提问作者Ashar
相关产品推荐
相关产品推荐

