43

zipfile からファイルを削除するために私が思いついた唯一の方法は、ファイルを削除せずに一時的な zipfile を作成し、その名前を元のファイル名に変更することでした。

Python 2.4 では、ZipInfo クラスに属性file_offsetがあったため、2 つ目の zip ファイルを作成し、解凍/再圧縮せずにデータを他のファイルにコピーすることができました。

これfile_offsetはpython 2.6にはありません。すべてのファイルを解凍してから再度圧縮して別のzipファイルを作成する以外のオプションはありますか?

zipfile 内のファイルを直接削除する方法はありますか? 検索しても何も見つかりませんでした。

4

4 に答える 4

50

次のスニペットは私にとってはうまくいきました(Zipアーカイブからすべての* .exeファイルを削除します):

zin = zipfile.ZipFile ('archive.zip', 'r')
zout = zipfile.ZipFile ('archve_new.zip', 'w')
for item in zin.infolist():
    buffer = zin.read(item.filename)
    if (item.filename[-4:] != '.exe'):
        zout.writestr(item, buffer)
zout.close()
zin.close()

すべてをメモリに読み込むと、2 つ目のファイルが不要になります。ただし、このスニペットはすべてを再圧縮します。

詳しく調べたところ、ZipInfo.header_offsetはファイルの先頭からのオフセットです。名前は誤解を招きますが、メインの Zip ヘッダーは実際にはファイルの最後に格納されています。私の16進エディタはこれを確認します。

したがって、あなたが遭遇する問題は次のとおりです: メイン ヘッダーのディレクトリ エントリも削除する必要があります。そうしないと、存在しないファイルを指してしまいます。削除するファイルのローカル ヘッダーもそのままにしておくと、メイン ヘッダーをそのままにしておくとうまくいくかもしれませんが、それについてはわかりません。古いモジュールでどのようにしましたか?

メインヘッダーを変更せずに開くと、「zipfile に X バイトがありません」というエラーが表示されます。これは、メイン ヘッダーを変更する方法を見つけるのに役立つ場合があります。

于 2009-02-04T23:31:37.063 に答える
10

あまりエレガントではありませんが、これが私がやった方法です:

import subprocess
import zipfile

z = zipfile.ZipFile(zip_filename)

files_to_del = filter( lambda f: f.endswith('exe'), z.namelist()]

cmd=['zip', '-d', zip_filename] + files_to_del
subprocess.check_call(cmd)

# reload the modified archive
z = zipfile.ZipFile(zip_filename)
于 2017-08-17T16:54:19.287 に答える
3

¹のルーチンdelete_from_zip_fileruamel.std.zipfile使用すると、ZIP 内のフル パスに基づいて、または ( re) パターンに基づいてファイルを削除できます。たとえば、使用してすべての.exeファイルを削除できますtest.zip

from ruamel.std.zipfile import delete_from_zip_file

delete_from_zip_file('test.zip', pattern='.*.exe')  

( の前のドットに注意してください*)。

これは mdm のソリューション (再圧縮の必要性を含む) と同様に機能しますが、( class を使用してInMemZipFile()) メモリ内に ZIP ファイルを再作成し、完全に読み取られた後に古いファイルを上書きします。


¹免責事項: 私はそのパッケージの作成者です。

于 2017-01-01T10:33:50.430 に答える