1000以上のpdfファイルを1つのpdfにマージする必要がある場合、
_input = PdfFileReader()
output = PdfFileWriter()
filename0000 ----- filename 1000
input = PdfFileReader(file(filename, "rb"))
pageCount = input.getNumPages()
for iPage in range(0, pageCount):
output.addPage(input.getPage(iPage))
outputStream = file("document-output.pdf", "wb")
output.write(outputStream)
outputStream.close()
_
上記のコードを実行します。input = PdfFileReader(file(filename500+, "rb"))
の場合、
エラーメッセージ:_IOError: [Errno 24] Too many open files:
_
これはバグだと思います。そうでない場合はどうすればいいですか?
最近、まったく同じ問題に出くわしたので、PyPDF2を掘り下げて、何が起こっているのか、どのように解決するのかを調べました。
注:filename
は整形式のファイルパス文字列であると想定しています。すべてのコードで同じと仮定する
短い答え
PdfFileMerger()
クラスの代わりにPdfFileWriter()
クラスを使用します。あなたのコンテンツにできるだけ似せるために、以下を提供しようとしました。
_from PyPDF2 import PdfFileMerger, PdfFileReader
[...]
merger = PdfFileMerger()
for filename in filenames:
merger.append(PdfFileReader(file(filename, 'rb')))
merger.write("document-output.pdf")
_
長い答え
PdfFileReader
とPdfFileWriter
を使用する方法は、各ファイルを開いたままにして、最終的にPythonがIOError 24を生成するようにすることです。具体的には、ページを追加するときPdfFileWriter
に、開いているPdfFileReader
内のページへの参照を追加しています(したがって、ファイルを閉じると、前述のIOエラーが発生します)。 Pythonはまだ参照されているファイルを検出し、ファイルハンドルを再利用してもガベージコレクション/自動ファイルクローズを行いません。これらは、コードのoutput.write(outputStream)
にあるPdfFileWriter
にアクセスする必要がなくなるまで開いたままになります。
これを解決するには、コンテンツのメモリにコピーを作成し、ファイルを閉じます。 PyPDF2コードでの冒険で、PdfFileMerger()
クラスにはすでにこの機能があることに気づいたので、ホイールを再発明する代わりに、代わりに使用することにしました。しかし、PdfFileMerger
の最初の見方が十分ではなく、特定の条件でコピーしか作成されないことを学びました。
私の最初の試みは次のように見え、同じIO問題を引き起こしていました:
_merger = PdfFileMerger()
for filename in filenames:
merger.append(filename)
merger.write(output_file_path)
_
PyPDF2のソースコードを見ると、append()
はfileobj
を渡す必要があり、merge()
関数を使用して、最後のページを新しいファイルとして渡すことがわかりますポジション。 merge()
は、fileobj
を使用して以下を実行します(PdfFileReader(fileobj)
で開く前に:
_ if type(fileobj) in (str, unicode):
fileobj = file(fileobj, 'rb')
my_file = True
Elif type(fileobj) == file:
fileobj.seek(0)
filecontent = fileobj.read()
fileobj = StringIO(filecontent)
my_file = True
Elif type(fileobj) == PdfFileReader:
orig_tell = fileobj.stream.tell()
fileobj.stream.seek(0)
filecontent = StringIO(fileobj.stream.read())
fileobj.stream.seek(orig_tell)
fileobj = filecontent
my_file = True
_
append()
オプションは文字列を受け入れ、それを行うとき、ファイルパスであると想定し、その場所にファイルオブジェクトを作成することがわかります。最終結果は、回避しようとしているものとまったく同じです。ファイルが最終的に書き込まれるまでファイルを開いたままにするPdfFileReader()
オブジェクト!
ただし、ファイルパス文字列またはのファイルオブジェクトをPdfFileReader
にすると(編集2を参照) append()
に渡される前にパス文字列のオブジェクト、StringIO
オブジェクトとしてコピーを自動的に作成し、_を許可しますPythonファイルを閉じます。
merger.append(file(filename, 'rb'))
を呼び出した後でも、PdfFileReader
オブジェクトがメモリ内で開いたままになる可能性があると他の人が報告しているように、より単純なwriter.close()
をお勧めします。
これが役に立てば幸いです!
編集:PyPDF
ではなく_PyPDF2
_を使用していると仮定しました。そうでない場合は、PyPDF2の開発において著者がPhaseitに公式の祝福を与えているため、PyPDFが維持されなくなるため、切り替えを強くお勧めします。
何らかの理由でPyPDF2にスワップできない場合(ライセンス、システム制限など)、PdfFileMerger
は利用できません。そのような状況では、PyPDF2のmerge
関数(上記で提供)からのコードを再利用して、ファイルのコピーをStringIO
オブジェクトとして作成し、それをコードでファイルオブジェクト。
編集2:merger.append(PdfFileReader(file(filename, 'rb')))
の使用に関する以前の推奨事項は、コメントに基づいて変更されました(@ Agostinoに感謝)。
Pdfrwパッケージは各ファイルを一度にすべて読み取るため、開いているファイルが多すぎるという問題はありません。 ここ は連結スクリプトの例です。
関連部分-inputs
が入力ファイル名のリストであり、outfn
が出力ファイル名であると仮定します。
from pdfrw import PdfReader, PdfWriter
writer = PdfWriter()
for inpfn in inputs:
writer.addpages(PdfReader(inpfn).pages)
writer.write(outfn)
免責事項:私は主なpdfrw著者です。
問題は、常に特定の数のファイルを開くことしか許可されていないことです。これを変更する方法があります( http://docs.python.org/3/library/resource.html#resource.getrlimit )が、これは必要ないと思います。
あなたが試すことができるのは、forループでファイルを閉じることです:
input = PdfFileReader()
output = PdfFileWriter()
for file in filenames:
f = open(file, 'rb')
input = PdfFileReader(f)
# Some code
f.close()
多分それは、あなたが多くのファイルを開いているということです。ループでf=file(filename) ... f.close()
を明示的に使用するか、with
ステートメントを使用できます。そのため、開いている各ファイルが適切に閉じられます。