【问题标题】:Read a binary file in java up to a specific "%%EOF" marker?将Java中的二进制文件读取到特定的“%%EOF”标记?
【发布时间】:2019-02-09 14:21:51
【问题描述】:

我需要在java中读取一个二进制文件并将其拆分(它实际上是一个包含许多pdf文件的二进制文件,每个文件之前都有一行“元数据”)。

二进制文件中的每个 pdf 项目都以 "%%EOF" 标记结尾。

我的第一次尝试,我将文件逐行读取为 UTF-8 文件,但这损坏了二进制数据!!

reader = new BufferedReader(new InputStreamReader(new FileInputStream(binaryFile), "UTF-8"));

String mdmeta;
while ((mdmeta = reader.readLine()) != null) {
    System.out.println("read file metadata: " + mdmeta);
    writeToFile("exploded-file-123");
}

和方法writeToFile

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fullFilename), "UTF-8"));

writer.write("%PDF-1.4\r\n");
String line;
while ((line = reader.readLine()) != null) {
    writer.write(line);
    writer.write("\r\n");
    if ("%%EOF".equals(line)) {
        writer.flush();
        return;
    }
}

...尽管这会将文件拆分为分解的项目,但这些二进制文件已损坏(当然是因为我将字节读取和写入为UTF-8 字符串...)

我认为我需要一个更底层的方法,使用 InputStream 的。

由于文件可能很大,因此变得复杂。想象一下我使用了一个缓冲区...我可以从文件中读取字节来填充缓冲区...然后我需要在缓冲区内查找"%%EOF"...并在上一个爆炸项和下一个。

或者如果"%%EOF" 落在缓冲区边缘,那么我可能会完全错过文件边界......

我想我正在寻找某种方式来readBytesUpUntil("%%EOF") - 有没有简单的方法可以做到这一点?

【问题讨论】:

  • 你知道这个二进制文件的编码吗?
  • 不完全确定我是否理解正确,但如果您知道原始编码,为什么不将%%EOF 转换为该编码并仅搜索该编码,始终保持原始编码
  • PDF 文件是二进制文件。您将它们视为文本。这很可能会损坏 PDF,无法修复。而是根据您从 InputStream 检索到的字节序列复制内容并将它们存储在 OutputStream 实例中。
  • @Eugene 我原本以为不是这样,但 PDF 文件显然有“无”编码。它们具有真正可以编码为任何内容的字节流
  • @mkl 你的意思是在内存中建立一个字节序列,直到找到%%EOF,然后再写入文件?

标签: java file pdf stream inputstream


【解决方案1】:

PDF 查看器在最后开始阅读文件。他们查找%%EOF,然后查找xref 表的开头,即交叉引用表。交叉引用表将所有对象映射到它们的字节偏移量。

例如:

  • 编号为 1 的对象从字节位置 12578 开始
  • 编号为 2 的对象从字节位置 158 开始
  • 编号为 3 的对象从字节位置 9821 开始
  • 编号为 4 的对象从字节位置 18792 开始
  • ...

等等。

PDF 查看器还会查找 /Catalog 的对象编号,即 PDF 文档的根字典。它通过转到交叉引用表中定义的字节偏移量来搜索/Catalog 对象。

PDF 查看器从该根字典获取/Pages 树的根。从/Pages 树中,它获取有关 PDF 中页面的信息,包括在哪里可以找到呈现页面所需的所有内容和资源。

所有这些都是通过在基于对象编号的交叉引用表中检索到的字节偏移量处对文件进行随机访问而发生的。

现在:

  • 假设您在 PDF 文件中插入一些任意字节,
  • 假设您没有调整交叉引用表,
  • 您希望 PDF 查看器如何找到呈现文档所需的对象?

此外,一个 PDF 可以包含多个 %%EOF 标记。线性化 PDF 就是这种情况,而增量更新的 PDF 就是这种情况。

此类 PDF 文件也必须从最后一个字节开始读取。在上一个版本的交叉引用表中,一些现有的对象将被替换并添加新的对象,但您仍然需要以前版本的交叉引用表,否则,您将无法渲染任何内容。

现在:

  • 假设您将拆分一个根据%%EOF 的出现而增量更新的文件,
  • 想象一下,您会将每个 sn-ps 保存为单独的文件,
  • 那么只有第一个文件是有效的 PDF 文件;所有连续文件都将缺少字体、重复使用的图像等资源。连续文件将不是完整的 PDF 文档。

简而言之:

根据%%EOF 的出现来拆分长PDF 文档是不明智的。即使将一系列有效的 PDF 文件粘合在一起,您也有可能最终破坏这些文件,因为单个 PDF 文件可能有不止一次出现 %%EOF

【讨论】:

  • 嗨 Bruno,哇 - pdf 工具的著名作者?感谢您停下来帮助像我这样的凡人。明天上班时我一定会重读你写的东西——谢谢!
  • 我正在查看一些寻找 pdf 文件“开始”的旧代码,每个 PDF 文件是否都有这样的开始标记? if ((pdfBuf[i] == 37) && (pdfBuf[i + 1] == 80) && (pdfBuf[i + 2] == 68) && (pdfBuf[i + 3] == 70))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-27
  • 2021-07-26
  • 2011-07-25
  • 1970-01-01
  • 2013-09-26
  • 2011-12-04
相关资源
最近更新 更多