You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docx4j使用FOP转PDF时如何删除临时图片或指定存储目录?

问题

在Linux环境下使用docx4j-export-fo通过XSL-FO将Docx转PDF时,含图片的文档转换后部分图片会被保存到/tmp目录,排查发现是AbstractConversionImageHandler.java在XSL-FO转换时存储图片导致的。

尝试设置FOSettings的ImageDirPath,但该设置仅对文档正文图片生效,页眉/页脚区域的图片仍会存入默认的/tmp目录——原因是FopAreeTreeHelper计算页眉/页脚区域大小时使用了FOP的默认设置,忽略了自定义的图片存储路径。

转换代码如下:

private static final String TEMP_IMAGE_DIR_PATH = "/tmp/images";

public static void convert(WordprocessingMLPackage wordMLPackage, OutputStream output) throws Exception {

    Mapper fontMapper = new BestMatchingMapper();
    wordMLPackage.setFontMapper(fontMapper);

    FOSettings foSettings = new FOSettings(wordMLPackage);
    foSettings.setApacheFopMime("application/pdf");
    foSettings.setImageDirPath(TEMP_IMAGE_DIR_PATH);
    foSettings.setFoDumpFile(null);

    FopFactoryBuilder fopFactoryBuilder = FORendererApacheFOP.getFopFactoryBuilder(foSettings);
    FopFactory fopFactory = fopFactoryBuilder.build();

    FOUserAgent foUserAgent = FORendererApacheFOP.getFOUserAgent(foSettings, fopFactory);

    Docx4J.toFO(foSettings, output, Docx4J.FLAG_EXPORT_PREFER_XSL);

    // Clean up, so any ObfuscatedFontPart temp files can be deleted
    if (wordMLPackage.getMainDocumentPart().getFontTablePart() != null) {
        wordMLPackage.getMainDocumentPart().getFontTablePart().deleteEmbeddedFontTempFiles();
    }
    foSettings = null;
    wordMLPackage = null;

    FileUtils.deleteDirectory(new File(TEMP_IMAGE_DIR_PATH));
}

目前仅能删除正文图片所在的TEMP_IMAGE_DIR_PATH目录,但页眉图片仍留在/tmp,不想删除/tmp下所有文件,询问是否有办法让Docx4j或FOP自动删除这些临时图片,或是为其指定存储目录?

解决方案

1. 为FOP全局指定临时文件目录

通过FopFactoryBuilder设置FOP的临时目录,覆盖默认的/tmp,这样页眉/页脚相关的临时图片会统一存储到自定义目录,转换后可直接删除该目录:

// 在创建FopFactoryBuilder后添加以下配置
fopFactoryBuilder.setTempDir(new File(TEMP_IMAGE_DIR_PATH));

修改后的完整代码片段:

FopFactoryBuilder fopFactoryBuilder = FORendererApacheFOP.getFopFactoryBuilder(foSettings);
// 设置FOP全局临时目录
fopFactoryBuilder.setTempDir(new File(TEMP_IMAGE_DIR_PATH));
FopFactory fopFactory = fopFactoryBuilder.build();

这样所有临时文件(包括页眉图片)都会存入/tmp/images,转换后执行FileUtils.deleteDirectory(new File(TEMP_IMAGE_DIR_PATH))即可全部清理。

2. 自定义AbstractConversionImageHandler实现

如果需要更精细的控制,可以自定义AbstractConversionImageHandler的子类,重写getImageFile方法,强制所有图片(包括页眉页脚的)使用指定的存储路径:

public class CustomImageHandler extends AbstractConversionImageHandler {
    private final String customImageDir;

    public CustomImageHandler(String customImageDir) {
        this.customImageDir = customImageDir;
    }

    @Override
    protected File getImageFile(String imageKey, String extension) throws Exception {
        File dir = new File(customImageDir);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return File.createTempFile(imageKey, "." + extension, dir);
    }
}

然后在转换前注册这个自定义处理器:

foSettings.setImageHandler(new CustomImageHandler(TEMP_IMAGE_DIR_PATH));

3. 手动清理指定前缀的临时文件

如果无法修改存储目录,可以在转换后根据临时文件的命名规律(docx4j生成的临时图片通常带有特定前缀,比如docx4j-),遍历/tmp目录删除匹配的文件:

File tmpDir = new File("/tmp");
File[] tmpFiles = tmpDir.listFiles((dir, name) -> name.startsWith("docx4j-") && name.endsWith(".png"));
if (tmpFiles != null) {
    for (File file : tmpFiles) {
        file.delete();
    }
}

注意:这种方式需要确保前缀匹配准确,避免误删其他程序的临时文件。

内容的提问来源于stack exchange,提问作者Aven

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 02:25:53