Zipファイルからファイルを削除するために思いついた唯一の方法は、削除するファイルを含まない一時的なzipファイルを作成してから、元のファイル名に名前を変更することでした。
python 2.4では、ZipInfoクラスには属性file_offset
、したがって、2番目のZipファイルを作成し、解凍/再圧縮せずにデータを他のファイルにコピーすることが可能でした。
この file_offset
がpython 2.6にないので、すべてのファイルを解凍してから再度圧縮して別のzipファイルを作成する以外のオプションはありますか?
Zipファイル内のファイルを直接削除する方法はありますか?検索しても何も見つかりませんでした。
次のスニペットは私のために働きました(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進エディタはこれを確認します。
したがって、発生する問題は次のとおりです。メインヘッダーのディレクトリエントリも削除する必要があります。そうしないと、存在しないファイルを指すことになります。削除するファイルのローカルヘッダーも保持している場合は、メインヘッダーをそのままにしておくと機能する可能性がありますが、それについてはよくわかりません。古いモジュールでどのようにそれを行いましたか?
メインヘッダーを変更せずに開くと、「zipファイルにXバイトがありません」というエラーが表示されます。 This は、メインヘッダーを変更する方法を見つけるのに役立つ場合があります。
あまりエレガントではありませんが、これが私がやった方法です:
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)
_delete_from_Zip_file
_ ¹のルーチン_ruamel.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のソリューション(再圧縮の必要性を含む)と同様に機能しますが、メモリ内にZipファイルを再作成し(クラス InMemZipFile()
を使用)、完全に読み取られた後に古いファイルを上書きします。
¹ 免責事項:私はそのパッケージの作者です。