Apache PDFBox自定义属性出现默认属性的原因及解决办法
问题描述
使用commons-logging-1.2.jar和pdfbox-2.0.27.jar(注:代码中使用PDFBox相关类,推测为pdfbox而非fontbox)读取PDF属性时,本应排除的CreationDate、ModDate、Title等属性仍出现在自定义属性列表中,通过if-else拦截无效。
代码示例
public List<String[]> readPDFProperties(String fileName, String filePath) { System.out.println("PDF"); System.out.println(fileName); List<String[]> arrList = new ArrayList<>(); try { PDDocument pdDocument = PDDocument.load(new FileInputStream(filePath)); PDDocumentInformation pdDocumentInformation = pdDocument.getDocumentInformation(); Set<String> set = pdDocumentInformation.getMetadataKeys(); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) { String value = iterator.next().trim(); if (value.equalsIgnoreCase("Author") || value.equalsIgnoreCase("CreationDate") || value.equalsIgnoreCase("Creator") || value.equalsIgnoreCase("ModDate") || value.equalsIgnoreCase("Title") || value.equalsIgnoreCase("Trapped") || value.equalsIgnoreCase("Producer") || value.equalsIgnoreCase("Subject") || value.equalsIgnoreCase("Keywords") || value.equalsIgnoreCase("Config File")) { } else { String creationDate = pdDocumentInformation.getCreationDate().getTime().toString() != null ? pdDocumentInformation.getCreationDate().getTime().toString() : ""; String modifiedDate = pdDocumentInformation.getModificationDate().getTime().toString() != null ? pdDocumentInformation.getModificationDate().getTime().toString() : ""; String[] arr = new String[14]; arr[0] = fileName; arr[1] = pdDocumentInformation.getTitle() != null ? pdDocumentInformation.getTitle() : pdDocumentInformation.getCOSObject().getString("Title") != null ? pdDocumentInformation.getCOSObject().getString("Title") : ""; arr[2] = pdDocumentInformation.getSubject() != null ? pdDocumentInformation.getSubject() : pdDocumentInformation.getCOSObject().getString("Subject") != null ? pdDocumentInformation.getCOSObject().getString("Subject") : ""; arr[3] = pdDocumentInformation.getCOSObject().getString("Author") != null ? pdDocumentInformation.getCOSObject().getString("Author") : ""; arr[4] = ""; arr[5] = ""; arr[6] = ""; arr[7] = pdDocumentInformation.getKeywords() != null ? pdDocumentInformation.getKeywords() : pdDocumentInformation.getCOSObject().getString("Keywords") != null ? pdDocumentInformation.getCOSObject().getString("Keywords") : ""; arr[8] = ""; //9 arr[9] = value != null ? value : ""; arr[10] = pdDocumentInformation.getCOSObject().getString(value) != null ? pdDocumentInformation.getCOSObject().getString(value) : ""; arr[11] = creationDate; arr[12] = modifiedDate; arr[13] = ""; //3 arrList.add(arr); } } if (arrList.size() == 0) { String creationDate = pdDocumentInformation.getCreationDate().getTime().toString() != null ? pdDocumentInformation.getCreationDate().getTime().toString() : ""; String modifiedDate = pdDocumentInformation.getModificationDate().getTime().toString() != null ? pdDocumentInformation.getModificationDate().getTime().toString() : ""; String[] arr = new String[14]; arr[0] = fileName; arr[1] = pdDocumentInformation.getTitle() != null ? pdDocumentInformation.getTitle() : pdDocumentInformation.getCOSObject().getString("Title") != null ? pdDocumentInformation.getCOSObject().getString("Title") : ""; arr[2] = pdDocumentInformation.getSubject() != null ? pdDocumentInformation.getSubject() : pdDocumentInformation.getCOSObject().getString("Subject") != null ? pdDocumentInformation.getCOSObject().getString("Subject") : ""; arr[3] = pdDocumentInformation.getCOSObject().getString("Author") != null ? pdDocumentInformation.getCOSObject().getString("Author") : ""; arr[4] = ""; arr[5] = ""; arr[6] = ""; arr[7] = pdDocumentInformation.getKeywords() != null ? pdDocumentInformation.getKeywords() : pdDocumentInformation.getCOSObject().getString("Keywords") != null ? pdDocumentInformation.getCOSObject().getString("Keywords") : ""; arr[8] = ""; //9 arr[9] = ""; arr[10] = ""; arr[11] = creationDate; arr[12] = modifiedDate; arr[13] = ""; //3 arrList.add(arr); } pdDocument.close(); } catch (Exception e) { e.printStackTrace(); } return arrList; }
CSV结果说明
CSV输出中,CreationDate、ModDate、Title等被标记为排除的属性,仍作为自定义属性条目出现,与预期不符。
问题根源
- 元数据键格式不匹配:PDFBox的
getMetadataKeys()返回的键默认带/前缀(比如/CreationDate),而代码中直接用equalsIgnoreCase("CreationDate")匹配,导致拦截逻辑失效。 - 空指针风险隐藏:原代码中
pdDocumentInformation.getCreationDate().getTime().toString()如果getCreationDate()返回null,会直接抛出空指针,后续逻辑无法正常执行。 - 判断逻辑冗余:用多个
||拼接判断容易漏写或出错,且未处理键的前缀问题。
解决方案
1. 统一处理元数据键前缀
先去除键的/前缀,再做匹配:
String value = iterator.next().trim(); if (value.startsWith("/")) { value = value.substring(1); }
2. 用集合存储排除键,简化判断
将需要排除的键存入HashSet,提升判断效率且易维护:
Set<String> excludedKeys = new HashSet<>(Arrays.asList( "Author", "CreationDate", "Creator", "ModDate", "Title", "Trapped", "Producer", "Subject", "Keywords", "Config File" ));
3. 修复空指针问题
安全获取日期字符串,避免直接链式调用导致空指针:
String creationDate = ""; if (pdDocumentInformation.getCreationDate() != null && pdDocumentInformation.getCreationDate().getTime() != null) { creationDate = pdDocumentInformation.getCreationDate().getTime().toString(); } String modifiedDate = ""; if (pdDocumentInformation.getModificationDate() != null && pdDocumentInformation.getModificationDate().getTime() != null) { modifiedDate = pdDocumentInformation.getModificationDate().getTime().toString(); }
完整修正后的代码
public List<String[]> readPDFProperties(String fileName, String filePath) { System.out.println("PDF"); System.out.println(fileName); List<String[]> arrList = new ArrayList<>(); // 定义需要排除的属性键集合 Set<String> excludedKeys = new HashSet<>(Arrays.asList( "Author", "CreationDate", "Creator", "ModDate", "Title", "Trapped", "Producer", "Subject", "Keywords", "Config File" )); try { PDDocument pdDocument = PDDocument.load(new FileInputStream(filePath)); PDDocumentInformation pdDocumentInformation = pdDocument.getDocumentInformation(); Set<String> set = pdDocumentInformation.getMetadataKeys(); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()) { String value = iterator.next().trim(); // 去除斜杠前缀 if (value.startsWith("/")) { value = value.substring(1); } // 跳过排除的键 if (excludedKeys.contains(value)) { continue; } // 安全获取日期 String creationDate = ""; if (pdDocumentInformation.getCreationDate() != null && pdDocumentInformation.getCreationDate().getTime() != null) { creationDate = pdDocumentInformation.getCreationDate().getTime().toString(); } String modifiedDate = ""; if (pdDocumentInformation.getModificationDate() != null && pdDocumentInformation.getModificationDate().getTime() != null) { modifiedDate = pdDocumentInformation.getModificationDate().getTime().toString(); } String[] arr = new String[14]; arr[0] = fileName; arr[1] = pdDocumentInformation.getTitle() != null ? pdDocumentInformation.getTitle() : (pdDocumentInformation.getCOSObject().getString("Title") != null ? pdDocumentInformation.getCOSObject().getString("Title") : ""); arr[2] = pdDocumentInformation.getSubject() != null ? pdDocumentInformation.getSubject() : (pdDocumentInformation.getCOSObject().getString("Subject") != null ? pdDocumentInformation.getCOSObject().getString("Subject") : ""); arr[3] = pdDocumentInformation.getCOSObject().getString("Author") != null ? pdDocumentInformation.getCOSObject().getString("Author") : ""; arr[4] = ""; arr[5] = ""; arr[6] = ""; arr[7] = pdDocumentInformation.getKeywords() != null ? pdDocumentInformation.getKeywords() : (pdDocumentInformation.getCOSObject().getString("Keywords") != null ? pdDocumentInformation.getCOSObject().getString("Keywords") : ""); arr[8] = ""; arr[9] = value != null ? value : ""; // 获取COS属性时加回斜杠前缀 arr[10] = pdDocumentInformation.getCOSObject().getString("/" + value) != null ? pdDocumentInformation.getCOSObject().getString("/" + value) : ""; arr[11] = creationDate; arr[12] = modifiedDate; arr[13] = ""; arrList.add(arr); } // 无自定义属性时的默认条目 if (arrList.size() == 0) { String creationDate = ""; if (pdDocumentInformation.getCreationDate() != null && pdDocumentInformation.getCreationDate().getTime() != null) { creationDate = pdDocumentInformation.getCreationDate().getTime().toString(); } String modifiedDate = ""; if (pdDocumentInformation.getModificationDate() != null && pdDocumentInformation.getModificationDate().getTime() != null) { modifiedDate = pdDocumentInformation.getModificationDate().getTime().toString(); } String[] arr = new String[14]; arr[0] = fileName; arr[1] = pdDocumentInformation.getTitle() != null ? pdDocumentInformation.getTitle() : (pdDocumentInformation.getCOSObject().getString("Title") != null ? pdDocumentInformation.getCOSObject().getString("Title") : ""); arr[2] = pdDocumentInformation.getSubject() != null ? pdDocumentInformation.getSubject() : (pdDocumentInformation.getCOSObject().getString("Subject") != null ? pdDocumentInformation.getCOSObject().getString("Subject") : ""); arr[3] = pdDocumentInformation.getCOSObject().getString("Author") != null ? pdDocumentInformation.getCOSObject().getString("Author") : ""; arr[4] = ""; arr[5] = ""; arr[6] = ""; arr[7] = pdDocumentInformation.getKeywords() != null ? pdDocumentInformation.getKeywords() : (pdDocumentInformation.getCOSObject().getString("Keywords") != null ? pdDocumentInformation.getCOSObject().getString("Keywords") : ""); arr[8] = ""; arr[9] = ""; arr[10] = ""; arr[11] = creationDate; arr[12] = modifiedDate; arr[13] = ""; arrList.add(arr); } pdDocument.close(); } catch (Exception e) { e.printStackTrace(); } return arrList; }
额外说明
获取COS对象属性值时,需要把去除的斜杠加回去(pdDocumentInformation.getCOSObject().getString("/" + value)),因为PDF元数据键在COS层均以/开头。
内容的提问来源于stack exchange,提问作者Chan
相关产品推荐
相关产品推荐

