【问题标题】:FileReader losing data when reading PDFFileReader 在阅读 PDF 时丢失数据
【发布时间】:2017-11-23 16:35:59
【问题描述】:

我只能以 JSON 格式向服务器发送数据,我需要将 PDF 文件与 JSON 中的其他表单数据一起发送。我虽然可以使用 base64 从中创建一个字符串,就像我在 SO 上找到的 this solution 一样:

let data = {foo: 1, bar: 2};
let reader = new FileReader();
reader.readAsDataURL(pdf);
reader.onload = () => {
  data.file = reader.result;
  $.ajax({type: 'POST', dataType: "json", data: JSON.stringify(data), ...});
}

但碰巧reader.result 不包含整个PDF(无论是我将其保存到文件而不是发送,还是从服务器取回)。在文本编辑器中,内容是相同的,但二进制编辑器说缺少一些字节。我的浏览器可以将其加载为 pdf 并显示标题,但页面为空白。

我也尝试过reader.readAsBinaryString 并自己使用btoa 转换为base64,但结果相同。

编辑:CodePen 示例:https://codepen.io/jdelafon/pen/eRWLdz?editors=1011

编辑:为了验证,我这样做了:

let reader = new FileReader();
reader.readAsBinaryString(pdf);
reader.onload = () => {
    let blob = reader.result;
    let file = new Blob([blob], {type: 'application/pdf'});
    let fileURL = window.URL.createObjectURL(file);
    // make it display in <embed>
};

pdf 的正文为空。如果我用原来的pdf 替换file,它就会完全显示出来。所以 FileReader 在这个过程中会丢失数据。

有没有更好的方法?是FileReader 的编码问题吗?

我也想像这样使用 FormData:

let data = {foo: 1, bar: 2};
let fd = new FormData();
fd.append('file', pdf);
data.file = btoa(fd);
$.ajax({type: 'POST', dataType: "json", data: JSON.stringify(data), ...});

但是现在当我从服务器取回数据时,JS 不知道它代表一个 FormData 对象,所以我不知道如何取回文件以在浏览器中显示。有可能吗?

【问题讨论】:

  • 您确定数据在浏览器中被截断,而不是在服务器上?
  • @Bergi 是的,因为我可以在发送之前直接在浏览器中显示,并且可以在通过 FileReader 之前与原始文件进行比较。我在我的问题中添加了代码。原始文件来自 .
  • 尝试删除dataType: "json" 我不确定它是否会起作用。这只是一个理论。
  • @perseusl 数据在我使用 Ajax 发送之前被截断。也许我应该在没有 json 上下文的情况下写一个新问题。加上如果是字符串,从json的角度看应该和其他字符串没有区别。
  • 但这不是您的问题...是的,您做错了,您不能简单地将 deprecated readAsBinaryString 的结果传递给 @987654337 @,这个二进制数据可能存在编码问题。如果你真的想这样做,你需要先把这个二进制字符串转换成一个arrayBuffer,然后从arrayBuffer中创建一个Blob。您的问题表明 readAsDataURL 不起作用,但我无法重现:codepen.io/anon/pen/gRWBxP?editors=1011

标签: javascript pdf filereader


【解决方案1】:

当您尝试 btoa 时,您离成功不远了,但您无法“btoa-ize” FormData。

reader.readAsBinaryString(pdf); // don’t use this! See edit below
reader.onload = () => {
  let b64payload = btoa(reader.result);
  $.ajax({
    type: 'POST',
    dataType: "json",
    data: JSON.stringify({ "file": b64payload }),
  });
}

我不确定为什么 readAsDataURL 解决方案失败了。


编辑:虽然不确定,但有人怀疑已弃用的 readAsBinaryString 方法可能是问题的根源。以下基于readAsDataURL 的解决方案正在运行:

reader.readAsDataURL(pdf);
reader.onload = () => {
  $.ajax({
    type: 'POST',
    dataType: "json",
    data: JSON.stringify({ "dataURL": reader.result }),
  });
};

【讨论】:

  • 我也试过了,但 PDF 被截断了。我觉得这种方法发送的是 pdf 的“内容”,而不是文件本身。为了验证,我按顺序执行,从您的b64payload,-> atob -> new Blob -> URL.createObjectURL -> 显示在&lt;embed&gt;。 pdf的正文是空的。原始 pdf 完全显示。
  • 这是一个使用 readAsDataURL 的工作示例:codepen.io/anon/pen/zzwyeP?editors=1011 接下来要做的是检查它是否在 ajax 之旅中幸存下来。
  • 非常感谢,这是我需要的示例 - 看起来像 Kaiido 的。我不明白为什么 b64 字符串无法在旅途中幸存下来。我刚刚检查了一下,确实如此。太棒了。
  • 所以我们可以说readAsBinaryString 是罪魁祸首来结束这个问题吗?此外,我们没有探索readAsArrayBuffer 选项。
  • 是的,我对 readAsDataURL 的实际使用方式有误解。如果您发布您的 sn-p 作为答案,我可以投票。
【解决方案2】:

Watilin 的答案没有添加,所以这里是从 Codepen 复制的工作 sn-p:

function onUpload(input) {  
  let originalFile = input.files[0];
  let reader = new FileReader();
  reader.readAsDataURL(originalFile);
  reader.onload = () => {
    let json = JSON.stringify({ dataURL: reader.result });

    // View the file
    let fileURL = JSON.parse(json).dataURL;
    $("#display-pdf").empty();
    $("#display-pdf").append(`<object data="${fileURL}"
      type="application/pdf" width="400px" height="200px">
    </object>`);

    // View the original file
    let originalFileURL = URL.createObjectURL(originalFile);
    $("#display-pdf").append(`<object data="${originalFileURL}"
      type="application/pdf" width="400px" height="200px">
    </object>`)
    .onload(() => {
      URL.revokeObjectURL(originalFileURL);
    });
  };
}

HTML:

<input id="file-input" type="file" onchange="onUpload(this)" />
<div id="display-pdf"></div>

【讨论】:

    猜你喜欢
    • 2020-04-01
    • 2018-02-10
    • 1970-01-01
    • 1970-01-01
    • 2019-10-18
    • 2021-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多