【问题标题】:Parallel Document Conversion ODT > PDF Libreoffice并行文档转换 ODT > PDF Libreoffice
【发布时间】:2013-02-13 01:19:20
【问题描述】:

我正在将数百个 ODT 文件转换为 PDF 文件,一个接一个需要很长时间。我有一个多核 CPU。是否可以使用 bash 或 python 编写脚本来并行执行这些操作? 有没有办法从命令行使用 libreoffice 并行化(不确定我是否使用正确的词)批处理文档转换? 我一直在 python/bash 中调用以下命令:

libreoffice --headless --convert-to pdf *appsmergeme.odt

subprocess.call(str('cd $HOME; libreoffice --headless --convert-to pdf *appsmergeme.odt'), shell=True);

谢谢!

提姆

【问题讨论】:

  • 您的意思是在多个 CPU 上运行单个 libreoffice 命令还是多次调用 libreoffice 并分别转换文件?第一种情况你什么都做不了,第二种情况很简单。
  • 嗯,我相信libreoffice 会阻止您同时运行多个 pdf 转换器。尝试创建多个进程只生成一个 .pdf 文件,其他进程失败。即使使用--nolockcheck 选项也会发生这种情况。所以,我相信你的问题的答案是:你不能。您应该使用不同的程序进行转换。
  • 我相信我曾经读过 libreoffice 总是只使用一个进程(也跨 writer、impress 等),这可能会让这不可能。
  • Bkuriu:我的意思是在多个 CPU 上运行 libreoffice,以便同时转换多个文件。
  • 除了 Libreoffice 之外,还有什么关于从 CLI ODT 进行批量转换的建议 > PDF?

标签: python bash libreoffice


【解决方案1】:

您可以将 libreoffice 作为守护程序/服务运行。请检查以下链接,也许它对您也有帮助:Daemonize the LibreOffice service

其他可能性是使用unoconv。 “unoconv 是一个命令行实用程序,可以将 OpenOffice 可以导入的任何文件格式转换为 OpenOffice 可以导出的任何文件格式。”

【讨论】:

    【解决方案2】:

    这个线程或答案是旧的。 我测试了 libreoffice 4.4,我可以确认我可以同时运行 libreoffice。 查看我的脚本。

    for odt in test*odt ; do
    echo $odt
    soffice --headless --convert-to pdf $odt & 
    ps -ef|grep ffice 
    done

    【讨论】:

      【解决方案3】:

      由于作者已经介绍了 Python 作为有效答案:

      import subprocess
      import os, glob
      from multiprocessing.dummy import Pool    # wrapper around the threading module
      
      def worker(fname, dstdir=os.path.expanduser("~")):
          subprocess.call(["libreoffice", "--headless", "--convert-to", "pdf", fname],
                          cwd=dstdir)
      
      pool = Pool()
      pool.map(worker, glob.iglob(
              os.path.join(os.path.expanduser("~"), "*appsmergeme.odt")
          ))
      

      multiprocessing.dummy 使用线程池而不是进程池就足够了,因为subprocess.call() 无论如何都会生成用于真正并行的新进程。

      我们可以直接设置命令以及当前工作目录cwd。无需为每个文件加载shell 即可。此外,os.path 支持跨平台互操作性。

      【讨论】:

        【解决方案4】:

        我用 golang 编写了一个程序来批量转换数千个 doc/xls 文件。

        • 将“根”变量值定义为要转换的文档路径
        • 已经转换成pdf的文档被跳过(如果没有,在visit()函数中注释检查条件)
        • 这里我使用 4 个线程(我有一个带有 4 个内核的 Intel i3)。您可以修改 main() 函数中的值

        有时 Libreoffice 可能无法转换某些文件,因此您应该打开它并手动将它们转换为 PDF。幸运的是,在我要转换的 16.000 个文档中,它们只有 10 个。

        package main
        
        import (
            "os/exec"
            "sync"
            "path/filepath"
            "os"
            "fmt"
            "strings"
        )
        
        // root dir of your documents to convert
        root := "/.../conversion-from-office/"
        
        var tasks = make(chan *exec.Cmd, 64)
        
        func visit(path string, f os.FileInfo, err error) error {
            if (f.IsDir()) {
                // fmt.Printf("Entering %s\n", path)
            } else {
                ext := filepath.Ext(path)
                if (strings.ToLower (ext) == "pdf") {
                } else {
        
        
                    outfile := path[0:len(path)-len(ext)] + ".pdf"
        
                    if _, err := os.Stat(outfile); os.IsNotExist(err) {
        
                        fmt.Printf("Converting %s\n", path)
        
                        outdir := filepath.Dir(path)
                        tasks <- exec.Command("soffice", "--headless", "--convert-to", "pdf", path, "--outdir", outdir)
                    }
                }
            }
            return nil
        } 
        
        
        func main() {
            // spawn four worker goroutines
            var wg sync.WaitGroup
        
            // the  ...; i < 4;... indicates that I'm using 4 threads
            for i := 0; i < 4; i++ {
                wg.Add(1)
                go func() {
                    for cmd := range tasks {
                        cmd.Run()
                    }
                    wg.Done()
                }()
            }
        
        
            err := filepath.Walk(root, visit)
            fmt.Printf("filepath.Walk() returned %v\n", err)
        
            close(tasks)
        
            // wait for the workers to finish
            wg.Wait()
        }
        

        【讨论】:

          【解决方案5】:

          unoconv 也有类似的问题。 unoconv 在内部使用 libreoffice。我们通过一次调用将多个文件发送到 unoconv 来解决它。因此,我们不是遍历所有文件,而是将文件集划分为桶,每个桶代表 o/p 格式。然后,我们会发出与桶一样多的调用。

          我很确定 libreoffice 也有类似的模式。

          【讨论】:

            【解决方案6】:

            未经测试可能有效:

            您/可能/能够:

            • 以某种公平的方式将文件分成多个并行批次,例如将它们全部放在文件夹中;
            • 创建一个不同的本地用户帐户来处理每个文件夹;
            • 以每个用户的身份连续运行 Libreoffice

            例如

             for paralleluser in timlev1 timlev2 timlev3 timlev4 ; do
                  su - $paralleluser -c \
                     "for file in /var/spool/pdfbatches/$paralleluser ; do \
                        libreoffice --headless --convert-to pdf $file ; done" 
             done
            

            通过使用su -,您不会意外地从实际会话中继承任何环境变量,因此并行进程不应相互干扰(除了争夺资源)。

            请记住,这些可能是 I/O 密集型任务,因此每个 CPU 内核运行 1 个可能不会大大加快您的速度。

            【讨论】:

            • Open/Libreoffice 不允许并行运行 soffice.exe
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-06-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-17
            相关资源
            最近更新 更多