如何让FileReader.readAsText结果匹配dataURL解码后的文本?
问题解决:让FileReader.readAsText与dataURL解码文本一致
问题原因
PNG是二进制文件,readAsText默认使用UTF-8编码读取时,会把无法识别的字节序列替换成�(U+FFFD),导致原始二进制数据丢失;而atob解码的是Base64对应的原始二进制字节,两者自然存在差异。
解决方案
调用readAsText时指定ISO-8859-1编码(又称Latin-1),该编码为单字节编码,每个字节都对应唯一字符,能完整保留二进制文件的所有字节信息,这样读取的文本就和atob解码结果完全一致。
修改后的代码
JavaScript部分
let inp = document.querySelector("input") async function read(file, type, encoding) { let reader = new FileReader() // 给readAsText传递指定编码 if (type === "readAsText" && encoding) { reader[type](file, encoding) } else { reader[type](file) } return new Promise((res) => { reader.addEventListener("load", _ => { res(reader.result) }) }) } function decodeDataUrl(dataurl) { return atob(dataurl.split(',')[1]) } inp.addEventListener("input", async _ => { let [file] = inp.files let dataURL = await read(file, "readAsDataURL") let textFromDataURL = decodeDataUrl(dataURL) console.log({text: textFromDataURL, length: textFromDataURL.length}); // 指定ISO-8859-1编码读取文本 let textFromReadAsText = await read(file, "readAsText", "ISO-8859-1") console.log({text: textFromReadAsText, length: textFromReadAsText.length}); // 验证两者一致性 console.log("文本是否一致:", textFromDataURL === textFromReadAsText) })
HTML部分(无需修改)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <input type="file"> </body> </html>
原理补充
- ISO-8859-1编码的字符范围覆盖0x00到0xFF,正好匹配二进制文件的所有字节值,每个字节直接对应一个Unicode字符,不会产生编码转换损失。
- 若要从读取的文本生成Blob/File对象,可通过以下方式还原二进制数据:
// 从ISO-8859-1编码的文本生成Blob function textToBlob(text) { let bytes = new Uint8Array(unescape(encodeURIComponent(text)).split('').map(c => c.charCodeAt(0))) return new Blob([bytes], {type: 'image/png'}) }
内容的提问来源于stack exchange,提问作者Fire Gamer
相关产品推荐
相关产品推荐

