Hầu hết các thuật toán nén chung đều hoạt động với độ chi tiết một byte một byte.
Hãy xem xét các chuỗi sau:
"XXXXYYYYXXXXYYYY"
- Một thuật toán Run-Length-Encoding sẽ nói: "đó là 4 'X', tiếp theo là 4 'Y', tiếp theo là 4 'X' , tiếp theo là 4 'Y' "
- Thuật toán Lempel-Ziv sẽ nói: " Đó là chuỗi 'XXXXYYYY', tiếp theo là cùng một chuỗi: vì vậy hãy thay thế chuỗi thứ hai bằng tham chiếu đến giá trị đầu tiên. "
- Thuật toán mã hóa Huffman sẽ cho biết: "Chỉ có 2 ký tự trong chuỗi đó, vì vậy tôi chỉ có thể sử dụng một bit cho mỗi biểu tượng".
Bây giờ, hãy mã hóa chuỗi của chúng tôi trong Base64. Dưới đây là những gì chúng tôi nhận được:
"WFhYWFlZWVlYWFhYWVlZWQ=="
Tất cả các thuật toán hiện đang nói: "Loại lộn xộn đó là gì?". Và họ không có khả năng nén chuỗi đó rất tốt.
Như một lời nhắc nhở, Base64 về cơ bản hoạt động bằng cách mã hóa lại các nhóm 3 byte trong (0 ... 255) thành các nhóm 4 byte trong (0 ... 63):
Input bytes : aaaaaaaa bbbbbbbb cccccccc
6-bit repacking: 00aaaaaa 00aabbbb 00bbbbcc 00cccccc
Mỗi đầu ra byte sau đó được chuyển thành ký tự ASCII có thể in được. Theo quy ước, những nhân vật này là (ở đây với một dấu ấn mỗi 10 ký tự):
0 1 2 3 4 5 6
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz/
Ví dụ, chuỗi ví dụ của chúng tôi bắt đầu với một nhóm ba byte bằng 0x58 trong hệ thập lục phân (mã ASCII của kí tự "X") . Hoặc ở dạng nhị phân: 01011000. Hãy áp dụng Base64 mã hóa:
Input bytes : 0x58 0x58 0x58
As binary : 01011000 01011000 01011000
6-bit repacking : 00010110 00000101 00100001 00011000
As decimal : 22 5 33 24
Base64 characters: 'W' 'F' 'h' 'Y'
Output bytes : 0x57 0x46 0x68 0x59
Về cơ bản, mô hình "3 lần so với 0x58 byte", mà là rõ ràng trong dòng dữ liệu ban đầu là không rõ ràng nữa trong dòng dữ liệu được mã hóa bởi vì chúng tôi đã chia các byte thành các gói 6 bit và ánh xạ chúng thành các byte mới mà bây giờ xuất hiện là ngẫu nhiên.
Hay nói cách khác: chúng tôi đã phá vỡ căn chỉnh byte ban đầu mà hầu hết các thuật toán nén dựa vào.
Bất kể phương thức nén nào được sử dụng, nó thường có tác động nghiêm trọng đến hiệu suất thuật toán. Đó là lý do tại sao bạn nên luôn luôn nén đầu tiên và mã hóa thứ hai.
Điều này thậm chí còn đúng hơn cho mã hóa: nén trước, mã hóa thứ hai.
EDIT - Một lưu ý về LZMA
Như MSalters nhận thấy, LZMA - mà xz đang sử dụng - đang làm việc trên suối chút chứ không phải là con suối byte.
Tuy nhiên, thuật toán này cũng sẽ bị ảnh hưởng từ mã hóa Base64 theo một cách mà chủ yếu là phù hợp với mô tả trước đây của tôi:
Input bytes : 0x58 0x58 0x58
As binary : 01011000 01011000 01011000
(see above for the details of Base64 encoding)
Output bytes : 0x57 0x46 0x68 0x59
As binary : 01010111 01000110 01101000 01011001
Thậm chí bằng cách làm việc ở cấp độ bit, nó dễ dàng hơn để nhận ra một mô hình trong chuỗi nhị phân đầu vào so với chuỗi nhị phân đầu ra.
"_base64-then-compress_ là tồi tệ hơn và chậm hơn đáng kể so với _compress-then-base64_" - chưa kể cả hai là dành cho tất cả ý định và mục đích không liên quan. – MSalters