如何将PDF的ArrayBuffer转为可存入JSON的字符串并解决btoa报错问题
嘿,这个问题我之前也碰到过!让我一步步帮你梳理清楚:
首先,你一开始用readAsBinaryString()导致PDF损坏是正常的——这个方法在处理二进制数据(尤其是像PDF这种包含非文本字节的文件)时,会因为编码处理的问题丢失或篡改部分内容,换成readAsArrayBuffer()绝对是正确的选择。
接下来的核心问题:怎么把ArrayBuffer转成能安全存入JSON的字符串?你之前用btoa(new TextDecoder("utf-8").decode(...))出错,是因为PDF是二进制文件,不是UTF-8编码的文本,用UTF-8解码会把很多二进制字节转换成无效的字符(比如�),而btoa()只接受符合Latin1编码的字符串(每个字符对应0-255的字节),所以才会报错。
下面给你两种靠谱的解决方案:
方法一:直接用readAsDataURL()(最简便)
FileReader的readAsDataURL()会直接把文件转换成Base64编码的字符串,格式是data:application/pdf;base64,xxxxxx,我们只需要把前缀去掉,剩下的就是可以存入JSON的字符串:
const reader = new FileReader(); reader.onload = function(e) { // 截取Base64部分(去掉data:application/pdf;base64,前缀) const pdfBase64 = e.target.result.split(',')[1]; // 构建你的包装器对象 const pdfWrapper = { pdfContent: pdfBase64, fileName: "example.pdf", createTime: new Date().toISOString(), // 其他你需要存储的额外信息 }; // 转成JSON字符串 const jsonStr = JSON.stringify(pdfWrapper); // 接下来就可以把jsonStr写入文件或者存储了 }; reader.readAsDataURL(你的PDF文件对象);
方法二:手动将ArrayBuffer转Base64(更灵活)
如果你坚持用readAsArrayBuffer(),可以先把ArrayBuffer转成Uint8Array,再用Latin1解码成字符串(因为Latin1是单字节编码,每个字节对应一个字符,不会破坏二进制数据),最后用btoa()转Base64:
const reader = new FileReader(); reader.onload = function(e) { const arrayBuffer = e.target.result; const uint8Array = new Uint8Array(arrayBuffer); // 用Latin1解码,保证每个字节都被正确转换为字符 const latin1Str = new TextDecoder("latin1").decode(uint8Array); // 转成Base64字符串 const pdfBase64 = btoa(latin1Str); // 同样构建包装器并转JSON const pdfWrapper = { pdfContent: pdfBase64, extraInfo: "自定义的额外信息" }; const jsonStr = JSON.stringify(pdfWrapper); }; reader.readAsArrayBuffer(你的PDF文件对象);
还原PDF的方法
当你需要从JSON里取出PDF内容时,只要把Base64字符串转回去就行:
// 假设已经从JSON里解析出包装器对象 const pdfWrapper = JSON.parse(读取到的JSON字符串); const pdfBase64 = pdfWrapper.pdfContent; // 把Base64转回Uint8Array const latin1Str = atob(pdfBase64); const uint8Array = new Uint8Array(latin1Str.length); for (let i = 0; i < latin1Str.length; i++) { uint8Array[i] = latin1Str.charCodeAt(i); } // 转成Blob,就可以预览或下载了 const pdfBlob = new Blob([uint8Array], { type: "application/pdf" }); const downloadUrl = URL.createObjectURL(pdfBlob); // 示例:创建下载链接 const a = document.createElement('a'); a.href = downloadUrl; a.download = pdfWrapper.fileName || "restored.pdf"; a.click(); URL.revokeObjectURL(downloadUrl); // 释放内存
这样处理后,PDF内容就不会损坏,也能顺利存入JSON文件啦!
内容的提问来源于stack exchange,提问作者cre8

