我有一个示例,用户可以从中选择一个文件(特别是PDF文件),将该文件转换为数组缓冲区,从该数组缓冲区构造回文件并下载该文件。按预期工作。
<input type="file" id="file_input" class="foo" />
<div id="output_field" class="foo"></div>
$(document).ready(function(){
$('#file_input').on('change', function(e){
readFile(this.files[0], function(e) {
//manipulate with result...
$('#output_field').text(e.target.result);
try {
var file = new Blob([e.target.result], { type: 'application/pdf' });
var fileURL = window.URL.createObjectURL(file);
var seconds = new Date().getTime() / 1000;
var fileName = "cert" + parseInt(seconds) + ".pdf";
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = fileURL;
a.download = fileName;
a.click();
}
catch (err){
$('#output_field').text(err);
}
});
});
});
function readFile(file, callback){
var reader = new FileReader();
reader.onload = callback
reader.readAsArrayBuffer(file);
}
现在假设我使用了reader.readAsText(file);
的{{1}} istead。在那种情况下,我会将文本转换为数组缓冲区,然后尝试做同样的事情。
reader.readAsArrayBuffer(file);
现在,如果我传递的PDF文件较小,并且只有文本,则可以使用该文件,但是当选择较大的文件和/或其中包含图像的文件时,将会下载计算的文件。
现在,我确实知道我正在努力使自己的生活更艰难。但是我想做的是以某种方式将结果从$(document).ready(function(){
$('#file_input').on('change', function(e){
readFile(this.files[0], function(e) {
//manipulate with result...
try {
var buf = new ArrayBuffer(e.target.result.length * 2);
var bufView = new Uint16Array(buf);
for (var i=0, strLen = e.target.result.length; i<strLen; i++) {
bufView[i] = e.target.result.charCodeAt(i);
}
var file = new Blob([bufView], { type: 'application/pdf' });
var fileURL = window.URL.createObjectURL(file);
var seconds = new Date().getTime() / 1000;
var fileName = "cert" + parseInt(seconds) + ".pdf";
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = fileURL;
a.download = fileName;
a.click();
}
catch (err){
$('#output_field').text(err);
}
});
});
});
function readFile(file, callback){
var reader = new FileReader();
reader.onload = callback
reader.readAsText(file);
}
转换为arrayBuffer,以便readAsText()
和readAsText()
都一样工作。
答案 0 :(得分:3)
readAsText
method不仅使UCS-16字符串中的字节可访问。相反,它会根据给定的文本编码格式将它们解码为文本,默认情况下为UTF-8。这将与您尝试读取的任何二进制数据混淆。正如您已经知道的那样,使用readAsArrayBuffer
。
您可以尝试使用TextEncoder
到encode
将文本返回到类型化数组,但这不能保证产生相同的结果:BOM被剥离,无效的UTF-8序列导致错误,如果不幸的话,甚至会发生Unicode标准化。
如果您明确指定单字节解码,可能会变得更容易,但实际上应该只使用readAsArrayBuffer
。
答案 1 :(得分:1)
Bergi已经回答了,您应该对二进制数据使用readAsArrayBuffer
而不是readAsText
,因为后者会解码字节序列,默认情况下为UTF-8。
UTF-8是可变长度编码,其中字符可以在1到4个字节之间。在不是UTF-8的二进制数据上运行解码器将无法恢复破坏二进制数据。
例如,仅0x00-0x7F逐字复制。 0xC2至0xDF是2字节序列的起始序列,是3字节序列的0xE0至0xEF,是4字节序列的0xF0至0xFF。 0x80到0xBF是序列的一部分。
以下是一些如何损坏它的示例(节点12.1):
ORIGINAL => DECODED from UTF-8 to UCS-2 => ENOCDED from UCS-2 to UTF-8
----------------------------------------------------------------------------------------------------------------------
[0xC2,0x80,0x80,0x80] => [0x0080,0xFFFD,0xFFFD] => [0xC2,0x80,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD]
[0xC3,0x80,0x80,0x80] => [0x00C0,0xFFFD,0xFFFD] => [0xC3,0x80,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD]
[0xE0,0x80,0x80,0x80] => [0xFFFD,0xFFFD,0xFFFD,0xFFFD] => [0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD]
[0xE1,0x80,0x80,0x80] => [0x1000,0xFFFD] => [0xE1,0x80,0x80,0xEF,0xBF,0xBD]
[0xF0,0x80,0x80,0x80] => [0xFFFD,0xFFFD,0xFFFD,0xFFFD] => [0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD]
[0xF1,0x80,0x80,0x80] => [0xD8C0,0xDC00] => [0xF1,0x80,0x80,0x80]
[0xF0,0x80,0x00,0x00] => [0xFFFD,0xFFFD,0x0000,0x0000] => [0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0x00,0x00]
[0x80,0x80,0x80,0x80] => [0xFFFD,0xFFFD,0xFFFD,0xFFFD] => [0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD]
[0x81,0x82,0x83,0x84] => [0xFFFD,0xFFFD,0xFFFD,0xFFFD] => [0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD,0xEF,0xBF,0xBD]
0xFFFD是替换字符,当无法将输入转换为已知代码点时使用。
答案 2 :(得分:-1)
这可能是我很久以前使用图形文件时遇到的问题。二进制文件具有特定格式是有原因的,例如cr / lf之类的东西可能就合法了。通过读取二进制文件作为文本并将其写回,实际上可能会在每行中额外增加cr / lf,从而丢弃文件中的原始格式/内容/指针。
要确认这一点,我将把您的原始文件,作为数组缓冲区读取/写入的内容带到一个Test文件,然后对文本作为文本的读取/写入的方式执行相同的操作。然后在两个文件之间进行二进制比较。
我敢打赌,您会无意间在里面得到多余的东西。