docx转PDF,创建Document程序卡死

版本:23.8
编程语言:java

现象:
在客户的阿里云云服务器(windows操作系统),
执行以下代码时(Document doc = new Document(new ByteArrayInputStream(bytes));),进程卡死

异常文件:
龙华站合同终止_通知函_20251125 补充非电 -1126 Clean.docx (37.7 KB)

jstack命令输出结果:

@ZhonghaoSun

您好,

感谢您使用 Aspose.Words for Java
针对您在阿里云 Windows 服务器上执行

Document doc = new Document(new ByteArrayInputStream(bytes));

时出现 卡死(进程不返回)的情况,下面提供几个常见的排查思路以及对应的解决方案。


1. 确认环境可用的系统字体

Aspose.Words 在解析 Word 文档时会尝试加载系统中可用的字体。
如果服务器上缺少常用的中文/西文字体(尤其是 SimSun、SimHei、Arial、Times New Roman 等),在某些包含复杂字体设置的 DOCX 中会触发内部的字体解析循环,从而导致卡死。

解决办法

  1. 安装常规字体

    • 在 Windows Server 上打开 “控制面板 → 字体”,确保已安装以下字体(至少):

      SimSun(宋体)
      SimHei(黑体)
      Microsoft YaHei(微软雅黑)
      Arial
      Times New Roman
      
  2. 使用自定义 FontSettings(不依赖系统字体):

    // 1) 创建 FontSettings 并指向本地字体文件夹
    FontSettings fontSettings = new FontSettings();
    fontSettings.setFontsFolder("C:/MyFonts", true);   // 将所有需要的 TTF/OTF 放到此文件夹
    
    // 2) 将 FontSettings 注入到 LoadOptions
    LoadOptions loadOptions = new LoadOptions();
    loadOptions.setFontSettings(fontSettings);
    
    // 3) 用 LoadOptions 加载文档
    Document doc = new Document(new ByteArrayInputStream(bytes), loadOptions);
    

    参考文档https://docs.aspose.com/words/java/working-with-fonts/

建议:先在本机(已装完整字体)运行一次代码,确认能够正常加载文档。如果本机可以,但服务器卡死,则几乎可以确认是字体缺失导致。


2. 使用最新的 Aspose.Words 版本

您当前使用的是 23.8,该版本在处理某些特殊结构的 DOCX(尤其是嵌入的 VML/SmartArt、图表或宏)时曾报告过死锁问题。
官方已在 24.3 及以后版本中修复相关 bug。

升级步骤

  1. 修改 Maven/Gradle/手动 jar 引用,更新为最新稳定版(截至本文撰写时为 24.6):

    <!-- Maven 示例 -->
    <dependency>
        <groupId>com.aspose</groupId>
        <artifactId>aspose-words</artifactId>
        <version>24.6</version>
    </dependency>
    
  2. 重新编译并部署到服务器。

参考文档https://docs.aspose.com/words/java/installation/


3. 使用 LoadOptions 明确指定加载格式

有时文件扩展名与内部标记不匹配,Aspose 需要额外的检测时间。将加载格式显式指定为 DOCX 能够避免内部格式探测的额外开销。

LoadOptions loadOptions = new LoadOptions(LoadFormat.DOCX);
Document doc = new Document(new ByteArrayInputStream(bytes), loadOptions);

4. 捕获并分析异常 / 线程堆栈

如果仍然卡死,可通过以下方式获取更详细的日志:

  1. 开启 Aspose.Words 调试日志(从 24.x 起支持):

    System.setProperty("aspose.words.debug", "true");
    System.setProperty("aspose.words.log", "aspose-words-debug.log");
    
  2. 使用 jstack 捕获完整线程堆栈(您已提供部分截图)。请重点查看 com.aspose.words.Document 构造函数内部的等待或锁定情况。若看到大量 java.lang.Object.wait(),通常是因为字体加载阻塞。

将完整的 jstack 输出(文本形式)贴回贴子,便于我们进一步定位。


5. 检查文档本身的异常结构

您提供的 龙华站合同终止_通知函_20251125 补充非电 -1126 Clean.docx 大小仅 37.7 KB,属于小文件,但可能含有 嵌入的 VML 图形、SmartArt、宏损坏的关系文件。可以尝试以下操作验证:

方法 操作步骤
OpenXML SDK 检查 使用 System.IO.Packaging.ZipPackage 打开文档,检查 word/_rels/document.xml.rels 中是否有指向不存在的目标。
Word 官方修复 在本地装有 Office 的机器上打开文档 → “文件 → 打开并修复”,然后保存为 docx,再上传服务器测试。
先转为 PDF 再回读 使用 Aspose.Words 将文档先转为 PDF(doc.save("tmp.pdf")),确认 PDF 能够生成。如果 PDF 正常,则说明文档读取本身没问题,卡死可能是 PDF 转换 环节的其它设置。

6. 示例完整代码(推荐做法)

import com.aspose.words.*;

import java.io.ByteArrayInputStream;

public class DocxToPdf {
    public static void main(String[] args) throws Exception {
        // 1) 读取文件字节(这里假设已经读取到 byte[] bytes)
        byte[] bytes = java.nio.file.Files.readAllBytes(
                java.nio.file.Paths.get("C:/temp/input.docx"));

        // 2) 配置字体(若服务器缺少系统字体)
        FontSettings fontSettings = new FontSettings();
        fontSettings.setFontsFolder("C:/MyFonts", true);   // 放入必需的中文字体

        // 3) 使用 LoadOptions 明确指定 DOCX 格式并注入 FontSettings
        LoadOptions loadOptions = new LoadOptions(LoadFormat.DOCX);
        loadOptions.setFontSettings(fontSettings);

        // 4) 加载文档
        Document doc = new Document(new ByteArrayInputStream(bytes), loadOptions);

        // 5) 保存为 PDF(可根据需要设置 PDF 保存选项)
        PdfSaveOptions pdfOptions = new PdfSaveOptions();
        pdfOptions.setSaveFormat(SaveFormat.PDF);
        doc.save("C:/temp/output.pdf", pdfOptions);

        System.out.println("转换完成。");
    }
}

7. 下一步怎么办?

  1. 确认服务器已安装常规字体(或使用自定义 FontSettings)。
  2. 升级至最新的 Aspose.Words 版本(≥ 24.3)。
  3. 使用 LoadOptions 明确指定加载格式,并重新测试。
  4. 若仍卡死,请将 完整的 jstack 文本启用的日志文件以及你尝试的代码贴回,我们将进一步定位。

期待您的反馈,祝您使用顺利!

链接汇总


如果还有其他细节(如完整堆栈、日志文件)请随时补充,我们会继续协助您定位根本原因。

@ZhonghaoSun 问题似乎在于多个线程同时尝试初始化类,导致并行类加载时发生死锁。具体表现为多个线程首次同时使用Aspose.Words时,会触发并行类加载导致死锁。建议提前同步初始化Aspose.Words。