PDF创建后无法打开,分方法填写表单域时报用户映射区段打开错误
问题原因
- 资源泄漏:你将
pdf2.close()写在try块内部,若字段填写过程中抛出异常,close逻辑不会执行,导致PDF文件句柄残留未释放。且iText默认使用内存映射方式读取PDF,该类文件句柄的释放依赖GC回收,即使正常执行close,也可能因为GC未触发出现临时锁占用,Windows系统下就会抛出「用户映射段打开」的错误。 - 路径逻辑错误:第一个方法读取
destE2写入dest2E2,第二个方法仍然读取原始的destE2并尝试写入已经被第一个方法操作过的dest2E2,不仅会出现锁冲突,还会导致第一个方法填写的内容全部丢失。 - 拆分方法的需求完全没必要:你拆分方法的原因是单方法内写数百行
setValue触发方法体积上限,完全可以通过批量映射填写的方式规避,不需要多轮操作文件。
最优解决方案(无需拆分方法)
将所有字段名和对应值存入Map,循环遍历批量填写,既不会触发方法体积上限,也不会有文件锁问题:
public void E2fillAll(String srcE2, String destE2) throws IOException { // 提前把所有字段和对应值存入Map,可单独抽方法生成该Map,不会占用当前方法体积 Map<String, String> fieldValueMap = buildFieldValueMap(); try (PdfDocument pdf = new PdfDocument(new PdfReader(srcE2), new PdfWriter(destE2))) { PdfAcroForm form = PdfAcroForm.getAcroForm(pdf, true); Map<String, PdfFormField> allFields = form.getFormFields(); for (Map.Entry<String, String> entry : fieldValueMap.entrySet()) { PdfFormField field = allFields.get(entry.getKey()); if (field != null) { field.setValue(entry.getValue()); } } form.flattenFields(); } catch (Exception x) { System.out.println(x.getMessage()); } } // 单独抽方法生成字段值映射,也可以按字段类型拆多个子方法,不会触发单方法体积上限 private Map<String, String> buildFieldValueMap() { Map<String, String> map = new HashMap<>(); map.put("fieldname1", stringname1); map.put("fieldname546", stringname546); // 其他字段赋值 return map; }
必须拆分方法的修复方案
如果业务逻辑要求必须拆分多方法操作,按以下规则修改:
- 用try-with-resources语法自动管理资源,保证无论是否报错都能正常关闭流
- 调整路径逻辑,后一个方法读取前一个方法的输出文件
- 禁用iText内存映射读取,避免GC未及时回收导致的锁残留
修改后示例代码:
public void E2fill(String srcE2, String tempDest) throws IOException { // 禁用内存映射读取 RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().createBestSource(srcE2), false, false); try (PdfDocument pdf2 = new PdfDocument(new PdfReader(raf), new PdfWriter(tempDest))) { PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true); Map<String, PdfFormField> fields2 = form2.getFormFields(); fields2.get("fieldname1").setValue(stringname1); // 其他第一批次字段填写 } catch (Exception x) { System.out.println(x.getMessage()); } } public void E2fill2(String tempDest, String finalDest) throws IOException { RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().createBestSource(tempDest), false, false); try (PdfDocument pdf2 = new PdfDocument(new PdfReader(raf), new PdfWriter(finalDest))) { PdfAcroForm form2 = PdfAcroForm.getAcroForm(pdf2, true); Map<String, PdfFormField> fields2 = form2.getFormFields(); fields2.get("fieldname546").setValue(stringname546); // 其他第二批次字段填写 form2.flattenFields(); } catch (Exception x) { System.out.println(x.getMessage()); } }
内容的提问来源于stack exchange,提问作者Gareth David
相关产品推荐
相关产品推荐

