目录
本文解决方案优化方案:
优化使用 itext 合并多个 pdf 方案,解决使用 Itext 合并 pdf 报错 PDF header signature not found_小庆_007的博客-CSDN博客
1、问题分析
相关依赖:
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
这是我第一版没有修改前报错的代码:
package com.lxq.utils;
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import java.io.FileOutputStream;
import java.util.List;
public class PdfUtil {
/**
* author luXiaoQing
* @param filePaths 需要拼接的多个pdf文件路径
* @param outputFilePath 合并后pdf输出路径
* @param outputFileName 合并后pdf文件名
*/
public static void mergePdf(List<String> filePaths, String outputFilePath, String outputFileName) {
if (filePaths.isEmpty()) {
return;
}
if (!Utils.checkNotNull(outputFilePath) || !Utils.checkNotNull(outputFileName)) {
return;
}
Document document = null;
PdfCopy copy = null;
PdfReader reader = null;
try {
document = new Document(new PdfReader(filePaths.get(0)).getPageSize(1));
copy = new PdfCopy(document, new FileOutputStream(outputFilePath + outputFileName));
document.open();
for (String filePath : filePaths) {
reader = new PdfReader(filePath);
int numberOfPage = reader.getNumberOfPages();
//注意 i 从 1 开始
for (int i = 1; i <= numberOfPage; i++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, i);
copy.addPage(page);
}
}
} catch (Exception e) {
System.out.println(e.getMessage() + e);
} finally {
if (Utils.checkNotNull(document)) {
document.close();
}
if (Utils.checkNotNull(reader)) {
reader.close();
}
if (Utils.checkNotNull(copy)) {
copy.close();
}
}
}
}
报错来源:
reader = new PdfReader(filePath);
看似没问题的代码,运行起来让人头大,问题的原因也让人无语(小小吐槽一下,诶嘿~)
通过 debug 发现了问题真正的原因是下面这三行代码:
document = new Document(new PdfReader(filePaths.get(0)).getPageSize(1));
copy = new PdfCopy(document, new FileOutputStream(outputFilePath + outputFileName));
document.open();
当我执行这三行代码后,参数 filePaths 中的第一个文件大小会变成 0 KB,后面我又去循环这个 filePaths, 在第一次循环时,new PdfReader(filePath); 就会读不到正确的文件。导致报错:com.itextpdf.text.exceptions.InvalidPdfException: PDF header signature not found.
for (String filePath : filePaths) {
reader = new PdfReader(filePath);
int numberOfPage = reader.getNumberOfPages();
for (int i = 1; i <= numberOfPage; i++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, i);
copy.addPage(page);
}
}
2、解决问题
真正困难的其实是:发现问题发生的真正原因,上面我们已经知道了错误的原因是由于 filePaths 中的第一个文件大小是0kb,我们在循环拼接之前将 File 保存为 byte[] ,其实应该有更好的解决方式。我这里有些取巧。大家如果有更好的解决方式,可以评论或私信我。有好的解决方案大家一起分享一下。
package com.lxq.utils;
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfCopy;
import com.itextpdf.text.pdf.PdfImportedPage;
import com.itextpdf.text.pdf.PdfReader;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
public class PdfUtil {
/**
* author luXiaoQing
* @param filePaths 需要拼接的多个pdf文件路径
* @param outputFilePath 合并后pdf输出路径
* @param outputFileName 合并后pdf文件名
*/
public static void mergePdf(List<String> filePaths, String outputFilePath, String outputFileName) {
if (filePaths.isEmpty()) {
return;
}
if (!Utils.checkNotNull(outputFilePath) || !Utils.checkNotNull(outputFileName)) {
return;
}
Document document = null;
PdfCopy copy = null;
PdfReader reader = null;
try {
List<byte[]> fileBytes = new ArrayList<byte[]>();
for (String filePath : filePaths) {
fileBytes.add(Files.readAllBytes(Paths.get(filePath)));
}
document = new Document(new PdfReader(filePaths.get(0)).getPageSize(1));
copy = new PdfCopy(document, new FileOutputStream(outputFilePath + outputFileName));
document.open();
for (byte[] fileByte : fileBytes) {
reader = new PdfReader(fileByte);
int numberOfPage = reader.getNumberOfPages();
//注意 i 从 1 开始
for (int i = 1; i <= numberOfPage; i++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, i);
copy.addPage(page);
}
}
} catch (Exception e) {
System.out.println(e.getMessage() + e);
} finally {
if (Utils.checkNotNull(document)) {
document.close();
}
if (Utils.checkNotNull(reader)) {
reader.close();
}
if (Utils.checkNotNull(copy)) {
copy.close();
}
}
}
}