You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript实现文件与二进制数据互转时文件损坏报错排查

问题说明

我通过<input />元素获取到存储在JavaScript File对象中的图片,希望将该文件转换为二进制字符串(非base64格式),再将得到的二进制数据还原为图片。
初始实现代码:

const file = input.files[0]
const reader = new FileReader()
reader.readAsBinaryString(file)
reader.onloadend = () => {
    const binaryString = reader.result // Binary string.
    const newFile = new File([binaryString], file.name, { type: file.type }) // Re-create file from binary data.
}

为生成的newFile调用FileReader.readAsDataURL生成data URL,通过该URL下载文件并尝试打开时,收到错误提示:

Not a JPEG file: starts with 0xef 0xbf

对原始file对象直接调用readAsDataUrl时一切正常,初步判断问题出在readAsBinaryString(file)调用或是new File([binaryString])实例化环节。
另外已知readAsBinaryString已被废弃,尝试使用readAsArrayBuffer实现相同逻辑时,出现了完全相同的问题。

错误原因

核心问题是字符串编码转换错误:

  1. JavaScript 原生字符串为UTF-16编码,当你把普通字符串传入File/Blob构造函数时,构造函数会默认将字符串按UTF-8编码序列化为字节流,而非直接将每个字符的低8位作为原始二进制字节写入。
  2. JPEG文件的起始字节是0xFF 0xD8,这两个值不属于合法的UTF-8单字节范围,在编码转换过程中会被替换为Unicode替换字符U+FFFD,该字符的UTF-8编码为0xEF 0xBF 0xBD,这就是报错里提到文件以0xef 0xbf开头的原因——原始文件头已经被错误编码破坏了。
  3. 你用readAsArrayBuffer复现问题,是因为你大概率拿到ArrayBuffer后先将其解码为普通字符串再传入File构造函数,触发了完全相同的编码转换错误。
正确实现方案

推荐方案:直接使用ArrayBuffer(符合标准,无兼容问题)

readAsBinaryString已经从Web标准中移除,优先使用readAsArrayBuffer读取原始二进制,读取结果不要转为普通字符串,直接传入File构造函数即可,不会触发任何编码转换:

const file = input.files[0]
const reader = new FileReader()
reader.readAsArrayBuffer(file)
reader.onloadend = () => {
    const arrayBuffer = reader.result
    // 直接传入ArrayBuffer,无编码损耗
    const newFile = new File([arrayBuffer], file.name, { type: file.type })
    // 生成的newFile与原文件完全一致,可正常读取、下载
}

兼容二进制字符串的方案

如果业务场景必须使用readAsBinaryString返回的二进制字符串,不要直接将字符串传入File构造函数,需要先手动将字符串转换为Uint8Array,逐字节写入原始字符码,避免UTF-8自动转码:

const file = input.files[0]
const reader = new FileReader()
reader.readAsBinaryString(file)
reader.onloadend = () => {
    const binaryString = reader.result
    const uint8 = new Uint8Array(binaryString.length)
    for (let i = 0; i < binaryString.length; i++) {
        uint8[i] = binaryString.charCodeAt(i)
    }
    const newFile = new File([uint8], file.name, { type: file.type })
    // 生成的newFile与原文件一致
}

内容的提问来源于stack exchange,提问作者Michal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 17:01:28