并行文档转换ODT> PDF Libreoffice

时间:2013-02-27 09:35:39

标签: python bash libreoffice

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

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

OR

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

谢谢!

6 个答案:

答案 0 :(得分:3)

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

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

答案 1 :(得分:1)

这个帖子或答案都是旧的。 我测试了libreoffice 4.4,我可以确认我可以同时运行libreoffice。 看我的剧本。

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

答案 2 :(得分:0)

我在golang中编写了一个程序来批量转换成千上万个doc / xls文件。

  • 将“root”变量值定义到要转换的文档的路径
  • 已将已转换的文档转换为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()
}

答案 3 :(得分:0)

我们遇到与 unoconv 类似的问题。 unoconv 在内部使用 libreoffice 。我们通过在一次调用中将多个文件发送到unoconv来解决它。因此,我们只是将文件集分区为桶,而不是迭代所有文件,每个桶代表o / p格式。然后我们拨打和桶一样多的电话。

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

答案 4 :(得分:0)

由于作者已经将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支持跨平台互操作性。

答案 5 :(得分:-1)

未经测试可能有效:

您/可能/能够:

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

e.g。

 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可能非常快。