Python和Ghostscript:OSError:打开的文件过多

时间:2017-01-24 04:16:47

标签: windows ghostscript

我在Windows上通过python 2.7运行ghostscript,将一堆1页PDF文件转换为TIFF图像。

from os import listdir, remove
from os.path import isfile, join
import ghostscript
import os
import time
import sys

#Assumption #1: The input folder, output_tif_folder and output_pdf_folder
#Assumption #2: Paths in windows use a backslash for reference. They have to be escaped characters - so use a \\ instead of a single \
#   eg: 'C:\\Users\\User\\Desktop\\Folder\\'
#Assumption #3: Required libraries are configured and installed properly. They are - i) ghostscript and ii) pyPdf

input_folder = 'C:\\Users\\User\\Desktop\\Folder\\test_files\\'; #Has to be the absolute path, ending with a slash
output_pdf_folder = 'C:\\Users\\User\\Desktop\\Folder\\pdf\\'; #Has to be an absolute path too, ending with a slash
output_tif_folder = 'C:\\Users\\User\\Desktop\\Folder\\tif\\' #Absolute path too, ending with a slash

onlyfiles = [f for f in listdir(input_folder) if isfile(join(input_folder, f))]

from pyPdf import PdfFileWriter, PdfFileReader

for pdfFile in onlyfiles:
    inputpdf = PdfFileReader(open(input_folder + pdfFile, 'rb'))
    for i in xrange(inputpdf.numPages):
        output = PdfFileWriter()
        output.addPage(inputpdf.getPage(i))
        with open(output_pdf_folder + pdfFile[:-4] + "_%s.pdf" % (i+1), "wb") as outputStream:
            output.write(outputStream)

def convertPdfTiff(inputfilename, outputfilename):
    args = [
    "pdf2tif", # actual value doesn't matter
    "-dNOPAUSE", "-dBATCH", "-dSAFER",
    "-sDEVICE=tiff24nc",
    "-sCompression=pack",
    "-sOutputFile=" + outputfilename,
    "-f",  inputfilename
    ]
    try:
        ghostscript.Ghostscript(*args)
    except:
        print 'something went wrong'

pagefiles = [f for f in listdir(output_pdf_folder) if isfile(join(output_pdf_folder, f))]
for pagefile in pagefiles:
    print 'Input: ' + output_pdf_folder + pagefile
    print 'Output: ' + output_tif_folder + pagefile[:-4] + ".tif"
    convertPdfTiff(output_pdf_folder + pagefile, output_tif_folder + pagefile[:-4] + ".tif")
    time.sleep(1)

转换大约114个文件后,我收到以下错误 - OSError: Too many open files

关于类似问题的其他帖子建议文件描述符应该优雅地关闭,但由于我没有打开它们(我假设ghostscript会这样做),我无法关闭它们。

处理这种情况的最佳方法是什么?

2 个答案:

答案 0 :(得分:0)

我不是Python开发人员,但在我看来你正在打开文件(如果我不对,我会道歉):

for pdfFile in onlyfiles:
    inputpdf = PdfFileReader(open(input_folder + pdfFile, 'rb'))

我没看到你关闭这些文件的位置。除此之外,Ghostscript肯定应该关闭所有自己的文件,虽然我已经看到Windows花了一些时间来实际关闭文件后GS处理它们。你可以尝试在那里放一个更长的time.sleep(),看看是否有帮助。

当然可以从命令行执行此操作(即直接使用Ghostscript而不是像您看到的那样使用DLL)并处理数百个文件。由于Ghostscript可执行文件使用相同的DLL,因此以这种方式使用它应该没有问题。

答案 1 :(得分:0)

这个问题可能已经解决了,但这是给可能碰到此页面的人的。

您使用

打开文件
inputpdf = PdfFileReader(open(input_folder + pdfFile, 'rb'))

行,但是您永远不会像KenS所说的那样关闭这些文件。要解决此问题,请像稍后在第二个with循环中所做的那样,使用for语句。

for pdfFile in onlyfiles:
    with open(input_folder + pdfFile, 'rb') as inputpdf:
        reader = PdfFileReader(inputpdf)
        for i in xrange(reader.numPages):
            output = PdfFileWriter()
            output.addPage(reader.getPage(i))
            with open(output_pdf_folder + pdfFile[:-4] + "_%s.pdf" % (i+1), "wb") as outputStream:
                output.write(outputStream)

这样,无论什么情况,inputpdf和outputStream都将关闭,因为这就是with语句的工作方式。即使您在with语句中遇到异常,该文件也会被关闭。

从这里https://docs.python.org/3/reference/compound_stmts.html#the-with-statement复制:

  

with语句用于包装具有以下内容的块的执行:   上下文管理器定义的方法(请参见“带语句”部分)   上下文管理器)。这允许常见的try…except…finally用法   要封装的样式以方便重用。

with_stmt ::=  "with" with_item ("," with_item)* ":" suite
with_item ::=  expression ["as" target]
     

使用一个“项目”执行with语句的过程如下   如下:

     
      
  1. 计算上下文表达式(with_item中给出的表达式)以获得上下文管理器。

  2.   
  3. 上下文管理器的__exit__()已加载以供以后使用。

  4.   
  5. 上下文管理器的__enter__()方法被调用。

  6.   
  7. 如果with语句中包含目标,则会将__enter__()的返回值分配给它。

  8.   
     

注意:

     

with语句保证如果__enter__()方法返回时没有错误,则将始终调用__exit__()。   因此,如果在分配给目标列表的过程中发生错误,它将   将被视为与套件内发生的错误相同   是。请参阅下面的步骤6。

     
      
  1. 该套件已执行。

  2.   
  3. 上下文管理器的__exit__()方法被调用。如果异常导致套件退出,则其类型,值和   追溯作为参数传递给__exit__()。不然三   提供了None个参数。

  4.   
     

如果套件由于异常而退出,并且返回值来自   __exit__()方法为假,则引发异常。如果   返回值是true,抑制了异常,然后执行   继续执行with语句之后的语句。

     

如果套件由于异常以外的其他原因退出,则   __exit__()的返回值将被忽略,执行将从   所采取的那种出口的正常位置。