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

Linux环境下Runtime.getRuntime().exec执行Calibre转MOBI失败求助

Linux下Runtime.exec执行Calibre转换HTML到MOBI失败的排查与解决

问题描述

在Linux开发机上通过Runtime.getRuntime().exec()调用Calibre的ebook-convert命令将HTML转换为MOBI时失败,生成的MOBI文件为空。该功能在Windows 10本地正常运行,尝试用{"bash", "-c", command}的方式执行命令仍无改善,且读取进程输入流无日志输出。

执行的命令示例:

/usr/src/calibre/ebook-convert /tmp/filesDirectory_mobi3970575619159760977/d7ed6792-b3cb-4761-bb6a-b9facf9e7a6c9250643820137116550.html /tmp/filesDirectory_mobi3970575619159760977/d7ed6792-b3cb-4761-bb6a-b9facf9e7a6c11909891397415910433.mobi

相关代码片段:

@Override
public Document convert(Document document, DocumentFormat documentFormat) {
    Document htmlDocument = htmlDocumentConverter.convert(document, documentFormat);
    try {
        log.info("Converting document from {} to {}", getSourceFormat().toString(), getTargetFormat().toString());
        CalibreConfigData calibreData = calibreConfig.getConfigurationData(CalibreConversion.HTML_TO_MOBI);

        Files.write(calibreData.getSourceFilePath(), htmlDocument.getContent());

        String command = calibreData.getCalibreCommand();
        String[] cmd = {"bash", "-c", command};
        var r = Runtime.getRuntime().exec(cmd);
        r.waitFor();
        log.warn("Process: " + new String(r.getInputStream().readAllBytes(), StandardCharsets.UTF_8));

        byte[] convertedFileAsBytes = Files.readAllBytes(calibreData.getConvertedFilePath());

        // Files.deleteIfExists(calibreData.getSourceFilePath());
        // Files.deleteIfExists(calibreData.getConvertedFilePath());
        // Files.deleteIfExists(calibreData.getFilesDirectoryPath());

        return new Document(convertedFileAsBytes);
    } catch (InterruptedException | IOException e) {
        log.error("Conversion failed due to problem: " + e);
        throw new ConversionException("Conversion failed due to problem: " + e);
    }
}

排查与解决步骤

1. 读取进程错误输出流

当前代码仅读取进程标准输出流,但ebook-convert的错误信息通常输出到错误流,导致无法获取失败原因。修改代码同时读取错误流:

var r = Runtime.getRuntime().exec(cmd);
// 先读取错误流,避免缓冲区阻塞进程
String errorOutput = new String(r.getErrorStream().readAllBytes(), StandardCharsets.UTF_8);
int exitCode = r.waitFor();
String output = new String(r.getInputStream().readAllBytes(), StandardCharsets.UTF_8);
log.warn("Process exit code: {}", exitCode);
log.warn("Process output: {}", output);
log.error("Process error: {}", errorOutput);

这一步能直接获取转换失败的具体原因,比如权限不足、依赖缺失、HTML格式错误等。

2. 手动在终端执行命令验证

直接在Linux终端运行给出的ebook-convert命令,确认是否能生成正常MOBI文件:

/usr/src/calibre/ebook-convert /tmp/filesDirectory_mobi3970575619159760977/d7ed6792-b3cb-4761-bb6a-b9facf9e7a6c9250643820137116550.html /tmp/filesDirectory_mobi3970575619159760977/d7ed6792-b3cb-4761-bb6a-b9facf9e7a6c11909891397415910433.mobi

如果手动执行失败,说明是Calibre配置或HTML文件本身的问题;如果手动执行成功,再排查Java进程的执行环境。

3. 检查Java进程权限

确保运行Java程序的用户对以下路径有读写权限:

  • HTML临时文件路径(/tmp/filesDirectory_mobi...)
  • MOBI输出路径
  • Calibre安装目录(/usr/src/calibre/)

可通过ps aux | grep java找到Java进程的运行用户,再用sudo -u <用户名> 执行上述ebook-convert命令验证权限是否足够。

4. 直接调用命令而非通过bash包装

如果命令没有复杂shell语法(如管道、通配符),直接拆分命令为数组调用,避免shell层的参数转义问题:

String[] cmd = {
    "/usr/src/calibre/ebook-convert",
    calibreData.getSourceFilePath().toString(),
    calibreData.getConvertedFilePath().toString()
};
var r = Runtime.getRuntime().exec(cmd);

5. 检查Calibre版本与依赖

Linux上的Calibre版本可能与Windows不同,部分HTML语法在旧版本中可能不兼容。执行/usr/src/calibre/ebook-convert --version查看版本,必要时升级到稳定版。同时确保系统安装了Calibre依赖的库(如Debian系的libfontconfig1、libxrender1等)。

6. 验证HTML文件格式

即使HTML文件有内容,也可能存在格式问题导致Calibre无法解析。尝试用简单测试HTML(如仅包含<h1>Test</h1>)进行转换,确认是否是原HTML的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 10:30:57