2009-02-04 28 views
30

Cách duy nhất tôi đưa ra để xóa tệp khỏi tệp zip là tạo một tệp nén tạm thời mà không cần tệp sẽ bị xóa và sau đó đổi tên tệp thành tên tệp gốc.Xóa tệp từ tệp nén với Mô-đun ZipFile

Trong trăn 2.4 lớp ZipInfo có thuộc tính file_offset, do đó, có thể tạo tệp zip thứ hai và sao chép dữ liệu vào tệp khác mà không cần giải nén/giải nén.

Thiếu file_offset trong python 2.6, vì vậy có một tùy chọn khác ngoài việc tạo một tệp zip khác bằng cách giải nén mọi tệp và sau đó nén lại không?

Có thể có cách trực tiếp xóa tệp trong tệp nén, tôi đã tìm kiếm và không tìm thấy bất kỳ thứ gì.

+0

tôi thấy chủ đề này trên bug tracker Python thảo luận về những khó khăn của việc loại bỏ các tập tin từ một tập tin zip: https: //bugs.python. org/issue6818 –

Trả lời

34

Đoạn sau đây làm việc cho tôi (xóa tất cả các file * .exe từ một kho lưu trữ Zip):

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() 

Nếu bạn đọc tất cả mọi thứ vào bộ nhớ, bạn có thể loại bỏ sự cần thiết cho một tập tin thứ hai. Tuy nhiên, đoạn mã này giải nén mọi thứ.

Sau khi kiểm tra kỹ hơn, ZipInfo.header_offset là giá trị bù trừ từ khi bắt đầu tệp. Tên này gây hiểu nhầm, nhưng tiêu đề Zip chính thực sự được lưu trữ ở cuối tệp. Trình chỉnh sửa hex của tôi xác nhận điều này.

Vì vậy, vấn đề bạn sẽ gặp phải là sau: Bạn cần xóa mục nhập thư mục trong tiêu đề chính cũng như nó sẽ trỏ đến tệp không tồn tại nữa. Việc để nguyên tiêu đề chính còn nguyên vẹn có thể hoạt động nếu bạn giữ tiêu đề cục bộ của tệp bạn đang xóa, nhưng tôi không chắc chắn về điều đó. Bạn đã làm thế nào với mô-đun cũ?

Không sửa đổi tiêu đề chính, tôi gặp lỗi "thiếu X byte trong tệp zip" khi tôi mở nó. This có thể giúp bạn tìm hiểu cách sửa đổi tiêu đề chính.

+0

cảm ơn, nhưng nếu tôi không sai - khi bạn nhìn vào zipfile.writestr bạn sẽ thấy rằng đây chỉ là một giải nén. Sẽ nhanh hơn nhiều khi chỉ sao chép các tệp đã nén mà không cần nhấn và sau đó nén chúng lại. – RSabet

+0

@RSabt Tôi đồng ý với mdm rằng giải nén và giải nén là lựa chọn khả thi duy nhất cho đến nay. Bằng cách này, muốn chỉ ra rằng mdm của mã giúp, nhưng tốt hơn sử dụng os.path.splitext() khi bạn sẽ làm điều gì đó nghiêm túc hơn. – RayLuo

+1

+1 cho tên var zin zout = D –

0

Thường lệ delete_from_zip_file từ ruamel.std.zipfile ¹ cho phép bạn xóa tệp dựa trên đường dẫn đầy đủ trong mã ZIP hoặc dựa trên (re) mẫu. Ví dụ. bạn có thể xóa tất cả các tập tin từ .exetest.zip sử dụng

from ruamel.std.zipfile import delete_from_zip_file 

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

(xin lưu ý các dấu chấm trước khi *).

Điều này hoạt động tương tự như giải pháp của mdm (bao gồm cả nhu cầu nén lại), nhưng tái tạo tệp ZIP trong bộ nhớ (sử dụng lớp InMemZipFile()), ghi đè tệp cũ sau khi được đọc đầy đủ.


¹ Tuyên bố từ chối trách nhiệm: Tôi là tác giả của gói đó.

2

Không rất thanh lịch nhưng đây là cách tôi đã làm nó:

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) 
+0

Đây là những gì tôi đã kết thúc. Xấu xí, nhưng 'ZipFile' dường như không có cách xóa hoặc cập nhật/thay thế tệp. – ArtOfWarfare

Các vấn đề liên quan