12

我正在将数百个 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);

谢谢!

蒂姆

4

6 回答 6

4

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

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

于 2013-03-06T21:12:34.517 回答
1

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

于 2017-06-13T08:49:35.747 回答
1

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

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

于 2015-11-13T00:09:21.753 回答
0

我在 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()
}
于 2016-04-05T09:01:19.737 回答
0

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

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

于 2017-06-13T08:10:01.110 回答
-2

未经测试可能有效:

您/可能/能够:

  • 以某种公平的方式将文件分成多个并行批次,例如将它们全部放在文件夹中;
  • 创建一个不同的本地用户帐户来处理每个文件夹;
  • 以每个用户的身份连续运行 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 个可能不会让您加速很多。

于 2013-03-06T21:16:43.743 回答