Tại sao Zip có thể nén một tệp nhỏ hơn nhiều tệp có cùng nội dung?


126

Giả sử rằng tôi có 10.000 tệp XML. Bây giờ giả sử rằng tôi muốn gửi chúng cho một người bạn. Trước khi gửi chúng, tôi muốn nén chúng.

Phương pháp 1: Đừng nén chúng

Các kết quả:

Resulting Size: 62 MB
Percent of initial size: 100%

Phương pháp 2: Zip mọi tệp và gửi cho anh ta 10.000 tệp xml

Chỉ huy:

for x in $(ls -1) ;  do   echo $x ; zip "$x.zip" $x ; done

Các kết quả:

Resulting Size: 13 MB
Percent of initial size: 20%

Phương pháp 3: Tạo một zip duy nhất chứa 10.000 tệp xml

Chỉ huy:

zip all.zip $(ls -1)

Các kết quả:

Resulting Size: 12 MB
Percent of initial size: 19%

Phương pháp 4: Ghép các tệp thành một tệp duy nhất & nén tệp

Chỉ huy:

cat *.xml > oneFile.txt ; zip oneFile.zip oneFile.txt

Các kết quả:

Resulting Size: 2 MB
Percent of initial size: 3%

Câu hỏi:

  • Tại sao tôi nhận được kết quả tốt hơn đáng kể như vậy khi tôi chỉ nén một tệp duy nhất?
  • Tôi đã mong đợi để có được kết quả tốt hơn nhiều khi sử dụng phương pháp 3 so với phương pháp 2, nhưng không. Tại sao?
  • Là hành vi này cụ thể zip? Nếu tôi thử sử dụng gziptôi sẽ nhận được kết quả khác nhau?

Thông tin bổ sung:

$ zip --version
Copyright (c) 1990-2008 Info-ZIP - Type 'zip "-L"' for software license.
This is Zip 3.0 (July 5th 2008), by Info-ZIP.
Currently maintained by E. Gordon.  Please send bug reports to
the authors using the web page at www.info-zip.org; see README for details.

Latest sources and executables are at ftp://ftp.info-zip.org/pub/infozip,
as of above date; see http://www.info-zip.org/ for other sites.

Compiled with gcc 4.4.4 20100525 (Red Hat 4.4.4-5) for Unix (Linux ELF) on Nov 11 2010.

Zip special compilation options:
    USE_EF_UT_TIME       (store Universal Time)
    SYMLINK_SUPPORT      (symbolic links supported)
    LARGE_FILE_SUPPORT   (can read and write large files on file system)
    ZIP64_SUPPORT        (use Zip64 to store large files in archives)
    UNICODE_SUPPORT      (store and read UTF-8 Unicode paths)
    STORE_UNIX_UIDs_GIDs (store UID/GID sizes/values using new extra field)
    UIDGID_NOT_16BIT     (old Unix 16-bit UID/GID extra field not used)
    [encryption, version 2.91 of 05 Jan 2007] (modified for Zip 3)

Chỉnh sửa: Dữ liệu meta

Một câu trả lời cho thấy sự khác biệt là dữ liệu meta hệ thống được lưu trữ trong zip. Tôi không nghĩ rằng đây có thể là trường hợp. Để kiểm tra, tôi đã làm như sau:

for x in $(seq 10000) ; do touch $x ; done
zip allZip $(ls -1)

Zip kết quả là 1,4 MB. Điều này có nghĩa là vẫn còn ~ 10 MB không gian không giải thích được.


34
Nếu tôi không nhầm, thì đây là phenomona khiến mọi người thực hiện .tar.gztrái ngược với việc chỉ nén toàn bộ thư mục.
corsiKa

18
Một câu hỏi tương tự đã được hỏi, tl; dr sử dụng kho lưu trữ 7zip rắn.
Dmitry Grigoryev

3
@sixtyfootersdude Là một thử nghiệm để xác thực một số câu trả lời, bạn có thể thử nén zip được sản xuất trong phương pháp 3 không? Tôi nghi ngờ điều này sẽ làm giảm kích thước tệp xuống một cái gì đó có thể so sánh với phương pháp 4.
Travis

7
Thay vì $(ls -1), chỉ sử dụng *: for x in *; zip all.zip *
muru

4
Nếu bạn muốn thực hiện nén chắc chắn với ZIP, đây là cách giải quyết: trước tiên, hãy tạo một ZIP không nén chứa tất cả các tệp của bạn. Sau đó, đặt ZIP đó vào trong một ZIP nén khác.
dùng20574

Câu trả lời:


129

Zip xử lý nội dung của từng tệp riêng biệt khi nén. Mỗi tệp sẽ có luồng nén riêng. Có sự hỗ trợ trong thuật toán nén (thường là DEFLATE ) để xác định các phần lặp lại. Tuy nhiên, không có hỗ trợ trong Zip để tìm sự dư thừa giữa các tệp.

Đó là lý do tại sao có quá nhiều không gian khi nội dung nằm trong nhiều tệp: nó đặt cùng một luồng nén vào tệp nhiều lần.


9
Đó cũng là lý do tại sao một số công cụ nén cung cấp cho bạn tùy chọn nén các tệp riêng biệt hoặc dưới dạng một thực thể. (Mặc dù nói chung điều đó cũng có nghĩa là bạn phải giải nén nhiều kho lưu trữ hơn so với nếu bạn muốn xem chỉ một tệp trong đó.)
JAB

28
@JAB: Các công cụ nén như 7z và rar sử dụng thuật ngữ lưu trữ "solid" để đóng gói nhiều tệp đầu vào đuôi thành các luồng nén lớn hơn. Với kích thước khối vừa phải như 64MiB, truy cập ngẫu nhiên vào một tệp có thể yêu cầu giải nén tối đa 64MiB dữ liệu từ khi bắt đầu khối nén mà bạn có. 7z có thể sử dụng sơ đồ nén LZMA hiệu quả hơn (nhưng chậm hơn để nén), đây là một lợi thế khác so với zip.
Peter Cordes

Bạn đang nói rằng đó there is no support in Zip to find redundancy between fileslà trong đặc tả tập tin zip?
Sixty feetersdude

6
@sixtyfootersdude Nhiều thuật toán nén, chẳng hạn như DEFLATE, hoạt động như một luồng. Để khôi phục đủ thông tin để giải nén một phần của luồng, bạn cần xử lý toàn bộ luồng cho đến thời điểm đó. Nếu họ cố gắng tìm sự dư thừa giữa các tệp, bạn sẽ phải giải nén tất cả 1000 tệp để đến tệp cuối cùng. Đây thường là cách tgz hoạt động, thực sự. Tuy nhiên, zip được thiết kế để cho phép bạn giải nén các tệp riêng lẻ. tgz được thiết kế để trở nên toàn diện hơn hoặc không có gì
Cort Ammon

1
@sixtyfootersdude - đúng rồi. Để diễn giải Cort: Thông số pkzip không hỗ trợ tệp chéo hoạt động. Nếu họ đã giải nén thì một tệp có thể yêu cầu toàn bộ tệp lưu trữ (và mọi tệp) được trích xuất.
James Snell

48

Nén ZIP dựa trên các mẫu lặp đi lặp lại trong dữ liệu sẽ được nén và quá trình nén sẽ tốt hơn khi tệp càng dài, vì càng có thể tìm thấy và sử dụng các mẫu dài hơn.

Đơn giản hóa, nếu bạn nén một tệp, từ điển ánh xạ mã (ngắn) thành các mẫu (dài hơn) nhất thiết phải có trong mỗi tệp zip kết quả; nếu bạn nén một tệp dài, từ điển sẽ được 'sử dụng lại' và phát triển thậm chí còn hiệu quả hơn trên tất cả nội dung.

Nếu các tệp của bạn thậm chí giống nhau một chút (như văn bản luôn luôn), việc sử dụng lại 'từ điển' sẽ trở nên rất hiệu quả và kết quả là tổng số zip nhỏ hơn nhiều.


3
ZIP không lưu trữ và nén. Điều này có nghĩa là ZIP nén từng tệp riêng lẻ, ngay cả khi tất cả chúng kết thúc trong cùng một tệp ZIP?
gerrit

2
nó giống như - hãy tưởng tượng bạn xóa một tệp duy nhất, bạn sẽ không muốn nó mất thêm nửa giờ để nén lại phần còn lại bằng một 'từ điển' mới. - ngoài ra, nó có thể giả định rằng các tệp khác nhau cần 'từ điển' rất khác nhau.
Aganju

2
Tôi không thấy lý do tại sao nó phải. Với các công cụ Unix, trước tiên tôi sẽ lưu trữ một tệp bằng tar, sau đó nén nó bằng gzip / bz2 / lzma. Thuật toán nén không quan tâm có bao nhiêu tệp được mã hóa trong kho lưu trữ. Ngoài ra, mức độ phổ biến của việc xóa một tệp khỏi tệp lưu trữ nén là phổ biến như thế nào? Tôi không nghĩ tôi đã từng làm điều đó.
gerrit

4
Tôi không đồng ý, và đó có lẽ là một cách tốt. Tôi đã không thiết kế hoặc viết ZIP. Tôi vừa nói những gì nó làm ...
Aganju

16
@gerrit Nó có vấn đề riêng của nó. Zip được thiết kế để cho phép bạn truy cập nhanh bất kỳ tệp nào trong kho lưu trữ - hãy thử giải nén một tệp từ kho lưu trữ 100 GiB UHA và bạn sẽ thấy lý do tại sao họ chọn cách này. Nó cũng được thiết kế để nối thêm - bạn có thể có mã zip dự phòng và chỉ cần tiếp tục thêm (hoặc thay thế) các tệp nếu cần. Tất cả điều này là một trợ giúp rất lớn khi sử dụng tài liệu lưu trữ. Sự đánh đổi là nếu bạn đang nén các tệp rất giống nhau ( không phổ biến lắm), thì nó không thể khai thác các điểm tương đồng để giảm kích thước lưu trữ.
Luaan

43

Trong Zip mỗi tệp được nén riêng. Ngược lại là 'nén rắn', đó là các tệp được nén cùng nhau. 7-zip và Rar sử dụng nén rắn theo mặc định. Gzip và Bzip2 không thể nén nhiều tệp để Tar được sử dụng trước tiên, có tác dụng tương tự như nén rắn.

Vì tệp xml có cấu trúc tương tự và có thể có nội dung tương tự nếu các tệp được nén cùng nhau, độ nén sẽ cao hơn.

Ví dụ: nếu một tệp chứa chuỗi "<content><element name="và máy nén đã tìm thấy chuỗi đó trong một tệp khác, nó sẽ thay thế nó bằng một con trỏ nhỏ cho khớp trước đó, nếu máy nén không sử dụng 'nén rắn' thì lần đầu tiên của chuỗi trong chuỗi tập tin sẽ được ghi lại dưới dạng chữ lớn hơn.


9

Zip không chỉ lưu trữ nội dung của tệp, nó cũng lưu trữ siêu dữ liệu tệp như sở hữu id người dùng, quyền, thời gian tạo và sửa đổi, v.v. Nếu bạn có một tệp, bạn có một bộ siêu dữ liệu; nếu bạn có 10.000 tệp, bạn có 10.000 bộ siêu dữ liệu.


3
Điểm tốt, nhưng dữ liệu meta hệ thống chỉ chiếm 1,4 MB dung lượng. Xem chỉnh sửa của tôi.
Sixty feetersdude

1
Tôi không quen thuộc với thuật toán zip, nhưng siêu dữ liệu không chỉ là thông tin tệp, mà còn những thứ như kích thước và từ điển, có thể là một số thông tin về phân phối ký tự. Một từ điển trên một tệp văn bản không trống sẽ khác không. Đó có thể là lý do tại sao bạn thấy siêu dữ liệu lớn hơn trong các tệp xml so với các tệp trống của bạn.
Ben Richards

Đây là suy nghĩ đầu tiên của tôi. Thông tin tiêu đề tệp Zip
WernerCD

Điều này chỉ giải thích sự khác biệt giữa 2 và 3 - chứ không phải 4.
Luaan

@Luaan Không, trong cả 2 và 3 siêu dữ liệu cho tất cả 10.000 tệp được bao gồm trong tệp zip hoặc tệp, vì vậy tổng kích thước tệp gần như cùng kích thước. Trong 4, chỉ có siêu dữ liệu cho một tệp và tệp zip nhỏ hơn nhiều.
Mike Scott

7

Một tùy chọn bị OP bỏ lỡ là nén tất cả các tệp cùng với việc nén đã tắt, sau đó nén zip kết quả với mức nén được đặt ở mức tối đa. Điều này mô phỏng đại khái hành vi của * nix .tar.Z, .tar.gz, .tar.bz, v.v., bằng cách cho phép nén để khai thác dự phòng qua các ranh giới tệp (thuật toán ZIP không thể thực hiện khi chạy trong một vượt qua). Điều này cho phép các tệp XML riêng lẻ được trích xuất sau, nhưng tối đa hóa việc nén. Nhược điểm là quá trình trích xuất đòi hỏi bước bổ sung, tạm thời sử dụng nhiều dung lượng đĩa hơn mức cần thiết cho một tệp .zip thông thường.

Với sự phổ biến của các công cụ miễn phí như 7-Zip để mở rộng họ tar cho Windows, thực sự không có lý do gì để không sử dụng .tar.gz hoặc .tar.bz, v.v., như Linux, OS X và BSD đều có công cụ bản địa để thao tác chúng.


gzip và bzip2 có thể thậm chí còn tồi tệ hơn vì chúng được thiết kế với các luồng nén, vì vậy chúng sẽ phải bắt đầu xuất dữ liệu nén trước khi tất cả dữ liệu cần nén.
rackandboneman

@rackandboneman: Đây là sự đánh đổi bạn phải thực hiện khi nén các tệp lớn hơn dung lượng bộ nhớ bạn muốn sử dụng tại thời điểm nén. (Và còn nữa, lượng thời gian CPU cần thiết để tìm bất cứ thứ gì tối ưu toàn cầu sẽ rất lớn.) Một từ điển nén khổng lồ cũng có thể tăng bộ nhớ cần thiết cho việc giải nén . Đây là một tùy chọn cho LZMA ( xz/ 7-zip). Dù sao, từ điển thích ứng có thể nhận được các mẫu khi chúng được nhìn thấy. Không giống như nó chỉ xây dựng một hệ thống mã hóa tĩnh dựa trên 32k đầu tiên. Đây là lý do tại sao gzip không hút.
Peter Cordes

Tôi thực sự thích "mẹo" này nếu bạn cần giữ nguyên định dạng zip. Tôi không đồng ý với "không có lý do gì để không sử dụng 7-zip". Tôi đang gửi một tệp cho một người bạn không có kỹ thuật, tôi muốn chắc chắn rằng họ sẽ có thể mở nó một cách dễ dàng. Nếu tôi đang gửi cho một khách hàng doanh nghiệp, thậm chí còn hơn thế.
Wowfunhappy

5

Định dạng nén zip lưu trữ và nén từng tệp riêng biệt. Nó không tận dụng sự lặp lại giữa các tệp, chỉ trong một tệp.

Ghép tệp cho phép zip tận dụng sự lặp lại trên tất cả các tệp, dẫn đến nén nhiều hơn.

Ví dụ: giả sử mỗi tệp XML có một tiêu đề nhất định. Tiêu đề đó chỉ xảy ra một lần trong mỗi tệp nhưng được lặp lại gần như giống hệt nhau trong nhiều tệp khác. Trong phương pháp 2 và 3 zip không thể nén cho điều này nhưng trong phương pháp 4 thì có thể.


3
Làm thế nào khác với một trong 3 câu trả lời hàng đầu đã được đăng 5 giờ trước đó?
Xen2050

1
@ Xen2050 Không có nhiều khác biệt, tôi chỉ nghĩ rằng tôi có thể giải thích rõ ràng hơn.
bonsaiOak

1
@BottoOak - sau đó thêm nhận xét vào câu trả lời hoặc chỉnh sửa chính xác nếu bạn có đủ đại diện. Nếu không, nhưng bình luận của bạn thêm rõ ràng, người khác có thể chọn điều này và chỉnh sửa bài viết bằng mọi cách.
AdamV

@AdamV Tôi thấy quan điểm của bạn. Câu trả lời của tôi hiện không thêm bất kỳ thông tin hữu ích nào, mặc dù nó được cho là đã làm khi tôi viết nó. Đã có những bình luận thích hợp dưới câu trả lời đầu tiên, vì vậy tôi cũng không thấy điểm nào trong việc thêm chúng. Bạn đang nói rằng tôi chỉ nên đóng câu trả lời của tôi? Điều gì có hại trong việc để nó mở?
bonsaiOak

4

Bên cạnh siêu dữ liệu Mike Scott đã đề cập, còn có thuật toán nén.

Khi nén một loạt các tệp nhỏ riêng lẻ, bạn sẽ phải rất may mắn để có thể nén chúng mà nó chỉ xảy ra để lấp đầy một khối nén. Khi nén một khối nguyên khối duy nhất, hệ thống chỉ có thể tiếp tục truyền dữ liệu đến thuật toán của nó, bỏ qua 'ranh giới' (vì thiếu từ tốt hơn) của các tệp riêng lẻ.

Ngoài ra ASCII được biết là có hệ số nén cao. cộng với xml thường rất lặp đi lặp lại làm cho siêu dữ liệu trở thành một khối lớn dữ liệu không thể nén dễ dàng như nội dung xml.

Cuối cùng, nếu bộ nhớ phục vụ đúng, zip sử dụng một cái gì đó như mã hóa từ điển, đặc biệt hiệu quả đối với các tệp ascii và thậm chí nhiều hơn trên XML do tính lặp lại của chúng

Giải thích về nén dữ liệu: http://mattmahoney.net/dc/dce.html


3

Hãy xem xét XML này:

<root>
  <element id="1" />
  <element id="2" /> 
  <other id="3" />
  ...
</root>

Một XML có cấu trúc rất lặp đi lặp lại, Zip tận dụng các lần lặp lại đó để xây dựng một từ điển có mẫu xuất hiện nhiều hơn và sau đó, khi nén, sử dụng ít bit hơn để lưu trữ nhiều mẫu lặp lại hơn và nhiều bit hơn để lưu trữ mẫu lặp lại ít hơn .

Khi bạn ghép các tệp đó, tệp nguồn (nguồn cho zip) lớn nhưng chứa các mẫu lặp lại nhiều hơn vì phân phối các cấu trúc nhàm chán của XML được khấu hao trong toàn bộ tệp lớn, tạo cơ hội để ZIP lưu trữ các mẫu đó sử dụng ít bit hơn.

Bây giờ, nếu bạn kết hợp XML khác nhau vào một tệp, ngay cả khi các tệp đó có tên thẻ hoàn toàn khác nhau, thuật toán nén sẽ tìm thấy phân phối mẫu tốt nhất trên tất cả các tệp và không phải tệp theo tệp.

Cuối cùng, thuật toán nén đã tìm thấy phân phối mẫu lặp lại tốt nhất.


-1

Ngoài câu trả lời 7-Zip còn có một cách tiếp cận khác không tốt nhưng sẽ đáng để thử nghiệm nếu vì lý do nào đó bạn không muốn sử dụng 7-Zip:

Nén tệp zip. Bây giờ, thông thường một tệp zip là không thể nén được nhưng khi nó chứa nhiều tệp giống hệt nhau, máy nén có thể tìm thấy sự dư thừa này và nén nó. Lưu ý rằng tôi cũng đã thấy một mức tăng nhỏ khi xử lý số lượng lớn tệp mà không cần dự phòng. Nếu bạn thực sự quan tâm đến kích thước, nó đáng để thử nếu bạn có rất nhiều tệp trong zip.


Điều đó chỉ hoạt động nếu bạn thực hiện zip đầu tiên với tính năng nén đã tắt như tôi đã đề cập ở trên.
Monty Harder

@MontyHarder Tôi đã thấy nó hoạt động với tính năng nén được bật.
Loren Pechtel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.