Gzip
Base64 olarak gzip, zlib ya da ham deflate’i yapıştırıp içini okuyun (hangisi olduğunu baytlar söyler) ya da metni üçünden birine sıkıştırın, tarayıcıda.
[
{
"name": "Zeynep",
"city": "İstanbul"
},
{
"name": "Yusuf",
"city": "Ankara"
},
{
"name": "Elif",
"city": "İzmir"
},
{
"name": "Mehmet",
"city": "Bursa"
},
{
"name": "Ayşe",
"city": "Antalya"
},
{
"name": "Emir",
"city": "Trabzon"
},
{
"name": "Defne",
"city": "Eskişehir"
},
{
"name": "Ali",
"city": "Konya"
}
]gzip olarak okundu.
- Sıkıştırılmamış bayt sayısı
- 415
- Sıkıştırılmış bayt sayısı
- 171
- Değişim
- %-58,8
- Base64 karakter sayısı
- 228
Üç sarmalayıcıda tek bir sıkıştırma ve deflate sözcüğü
gzip, zlib ve ham deflate tek bir sıkıştırmadır: üç ayrı şekilde sarmalanmış DEFLATE. DEFLATE sıkıştırmasının kendisini RFC 1951 tanımlar: baytlar bloklara bölünür ve her blok, bir baytı ya da daha önce geçen bir parçanın kopyasını temsil eden kodlarla yazılır. gzip’in sarmalayıcısı, yani RFC 1952, öne en az on baytlık bir başlık, arkaya da sekiz bayt koyar: özgün baytların CRC-32 değeri ve uzunlukları; zlib’in sarmalayıcısı, yani RFC 1950, öne iki bayt, arkaya bir Adler-32 değeri koyar; ham deflate ise hiç sarmalayıcısı olmayan sıkıştırmadır. İçerideki sıkıştırılmış veri üçünde de aynı olabilir; bu yüzden aradaki farkın tamamı sarmalayıcıdır.
Adların birbirine karıştığı yer deflate sözcüğüdür. HTTP’ye göre Content-Encoding: deflate, zlib’in sarmalayıcısı demektir ve RFC 9110, bazı sunucuların ham deflate’i de yine bu adla gönderdiğini belirtir. Tarayıcının kendi sıkıştırıcısı HTTP’yi izler: zlib’in sarmalayıcısını deflate adıyla, ham deflate’i ise deflate-raw adıyla anar. .NET’in DeflateStream sınıfı ve PHP’nin gzdeflate işlevi ham deflate yazar; PHP’nin gzcompress işlevi ve Python’un zlib.compress işlevi ise zlib’in sarmalayıcısını yazar. Yani deflate etiketli baytlar ikisinden biri olabilir ve hangisi olduğunu yalnızca baytlar söyleyebilir.
Bu yüzden sayfa, sıkıştırmayı açarken sarmalayıcıyı baytlardan okur ve hangisini okuduğunu çıkan sonucun altında söyler: “gzip olarak okundu”, “zlib olarak okundu” ya da “ham deflate olarak okundu”. Bunu baytlar belirler: gzip her zaman 1f 8b ile başlar; zlib’in ilk iki baytı birlikte tek bir sayı olarak okunduğunda 31’in katıdır; hiçbir kodlayıcı da ham deflate’i bu ikisinden biriyle başlatmaz. Adı .gz ile biten ama zlib içeren bir dosya zlib olarak okunur ve adla baytların uyuşmadığını söyleyen bir bildirim çıkar; üçünden hiçbirinde olmayan baytlar ise reddedilir, açılacak bir şey yoktur. Sıkıştırırken sarmalayıcıyı siz seçersiniz ve siz başka birini seçene kadar gzip’tir.
Yükler nereden gelir, H4sI ve eJ nedir
Sıkıştırılmış baytlar bir geliştiriciye birkaç şekilde ulaşır: Content-Encoding başlığı gzip ya da deflate diyen bir HTTP yanıtının gövdesi olarak, bir dosya olarak ya da Base64 veya on altılık olarak yazılmış metin olarak. Her gzip akışı aynı üç baytla başlar, 1f 8b 08 — iki imza baytı ve sıkıştırma yönteminin numarası, yani DEFLATE — ve üç bayt tam olarak dört Base64 karakteri eder; bu yüzden Base64 olarak yazılmış gzip her zaman H4sI ile başlar. Bir CloudWatch Logs aboneliğinin her kaydın verisinde bir Lambda işlevine ya da bir Kinesis akışına teslim ettiği şey budur; Helm’in bir release’i saklama biçimi de budur: release’in JSON’u gzip ile sıkıştırılır, sonra Base64 olarak yazılır. Helm bir release’i bir Kubernetes Secret nesnesinde tuttuğunda, onu doğrudan Secret nesnesinden okumak Base64 içinde Base64 verir, çünkü bir Secret nesnesi verisini kendine ait bir Base64 olarak tutar; Base64 aracı bu dış katmanı çözer ve ortaya bu sayfanın okuduğu H4sI… çıkar.
zlib’in iki başlık baytı yöntemini, penceresini ve yazıldığı düzeyi belirtir; bu yüzden zlib’in varsayılan penceresiyle Base64 karşılığı dört şekilden biriyle başlar: varsayılan düzeyde eJ ile — aksi istenmedikçe Python’un zlib.compress işlevinin yazdığı budur —, onun altındaki düzeylerde eA ya da eF ile, üstündekilerde ise eN ile. Ham deflate’in hiçbir imzası yoktur ve Base64 karşılığı, ilk bloğu nasıl denk gelirse öyle başlar.
“Sıkıştırılmış veri gösterimi” seçicisi, sayfanın bu baytları metin olarak nasıl okuyup yazdığını belirler: sayfanın açılıştaki seçimi olan “Base64” ya da “On altılık”. Seçim iki yönde de geçerlidir ve sayfa onu sizin yerinize asla değiştirmez, çünkü her on altılık rakam aynı zamanda bir Base64 karakteridir; bu yüzden 1f8b0800 ikisinde de metindir ve her birinde farklı baytlardır. Base64, standart alfabeyle ya da URL güvenli alfabeyle, dolgulu ya da dolgusuz, boşlukları ve satır sonlarını atlayarak okunur; dolgulu yazılır, “URL güvenli” seçeneği açıkken de URL güvenli ve dolgusuz yazılır. On altılık, boşluklu çiftler hâlinde yazılır; boşluklu ya da bitişik, önünde 0x ile ya da bir on altılık döküm olarak okunur — 0x ayrıca T-SQL’in ikili bir değeri yazma biçimidir, SQL Server’ın COMPRESS() işlevinin döndürdüğü gzip gibi. Base64 olarak okunan on altılık başarısız olduğunda ya da on altılık olarak okunan Base64, on altılıkta olmayan bir karakterde reddedildiğinde ve her iki durumda da metnin tamamı öteki şekilde okunduğunda, bir bildirim bunu söyler ve yanında geçiş yapan bir düğme durur; siz o düğmeye tıklamadıkça hiçbir şey değişmez.
Bir akışı okumak: üyeler, ardından gelen baytlar ve erken bir bitiş
RFC 1952’ye göre bir gzip dosyası art arda gelen üyelerden oluşur: her biri kendi başlığına ve kuyruğuna sahip eksiksiz gzip akışları. cat a.gz b.gz komutu böyle bir dosya oluşturur; GNU gzip kılavuzunun kendi örneğindeki gibi gzip -c file >> archive.gz ile bir dosyaya ekleme yapmak da öyle; gunzip her üyeyi okur ve içerdiklerini birleştirir. Bu sayfa da onları aynı şekilde okur: her üye okunur ve denetlenir, içerdikleri birleştirilmiş olarak gösterilir ve bir bildirim kaç üye okunduğunu söyler. gzip okuyan her program bunu yapmaz. Tarayıcının kendi sıkıştırma açıcısının uyduğu standart, bir gzip akışında tek bir üyeye izin verir ve ikincisini hata sayar; Python’un zlib.decompress işlevi ise ilkinden sonra tek söz söylemeden durur.
Sonun ardından gelen ve hiçbir üye başlatmayan baytlar reddedilmez, atlanır, çünkü onlardan önceki her şey eksiksizdir ve denetlenmiştir; bir bildirim de bunların kaç tane olduğunu, hangi ofsetten başladıklarını ve hepsinin sıfır olup olmadığını söyler. Oradaki sıfırlar dolgudur — GNU gzip kılavuzu bunlarla manyetik bantlarda, bir bloğun sonuna kadar yazılmış hâlde karşılaşır — ve gunzip bunları sessizce geçer; başka baytları ise sondaki çöpün yok sayıldığını söyleyen bir uyarıyla geçer, Python’un gzip.decompress işlevi ise dosyayı reddeder. Aynısı bir zlib akışının Adler-32 değerinden sonra ve ham bir akışın son bloğundan sonra da geçerlidir, ancak ham deflate denetlenecek bir sağlama toplamı taşımaz.
Yarıda kesilmiş bir yapıştırma ya da yarıda durmuş bir indirme gibi, sonu gelmeden biten bir akış, ulaştığı yere kadar gösterilir ve sağlama toplamının denetlenmediğini söyleyen bir bildirim çıkar. Bozuk bir akış reddedilir ve hiçbir kısmı gösterilmez. Bu, gunzip’ten daha katıdır: gunzip, açtığı kısmı, onun yanlış olduğunu ortaya çıkaran sağlama toplamına varmadan önce yazar; ama değişmiş bir bit, herhangi bir şey onu belli etmeden önce bir süre sessizce çözülebilir, bu yüzden hasar ortaya çıkmadan önce çıkan kısım bile şimdiden yanlış olabilir. Ayrıca bir konum da verilmez, çünkü bir çözücünün hasarı fark ettiği yer, hasarın olduğu yer değildir. Önceden tanımlanmış bir sözlük isteyen bir zlib akışı da kendine ait bir cümleyle reddedilir: akış, sıkıştırıcısına önceden verilen baytların hangileri olduğunu belirtir ama onları taşımaz, bu yüzden onu okuyacak bir şey yoktur.
Çıkan sonuç, “Bayt gösterimi” seçicisinin söylediği gibi yazılır: UTF-8 olarak “Metin” ya da “On altılık”. Çoğu zaman bu bir JSON’dur; JSON biçimlendirici onu düzenler ve denetler, bozulduğu satırı ve sütunu gösterir. gzip ile sıkıştırılmış bir resim ya da arşiv metin değildir; bu yüzden “Metin” seçiliyken baytlarının UTF-8 olmayan her dizisi U+FFFD olarak görünür ve bu dizileri sayan bir bildirimin yanında baytları on altılık olarak gösteren bir düğme durur; “İndir” düğmesi her iki durumda da baytların kendisini kaydeder. Sonucun altındaki bir satır, ilk üyenin başlığının sakladıklarını gösterir: bir ad, UTC olarak bir zaman ve bir yorum; saklanan ad, “İndir” düğmesinin kaydettiği dosyaya asla ad olmaz. Sayfanın bir seferde açtığı en fazla miktarı aşan bir çıktı orada durur ve bu boyutu belirten bir bildirim çıkar; bir gzip’in kuyruğu bu sınırı aşan bir uzunluk belirtiyorsa sayfa bunu iş sürerken söyler.
Küçük bir girdi neden büyür ve Base64 ne ekler
Sıkıştırma tekrarı bularak kazanır ve kısa bir metinde pek tekrar yoktur; her sarmalayıcının ise kendine ait bir bayt maliyeti vardır: başlık başka bir şey saklamadığında gzip’in başlığı ve kuyruğu 18 bayt eder, zlib’inkiler 6 bayt; ham deflate’in hiç yoktur, ancak DEFLATE bloklarını işaretlemek için birkaç bit harcar. Böylece 13 bayt olan Hello, world! gzip olarak 33 bayt, zlib olarak 21 bayt, ham deflate olarak 15 bayt olur. Bir sonucun altındaki boyut satırı her iki taraftaki baytları ve aralarındaki değişimi sayar — o gzip için %+153,8 — ve bir sonuç büyüdüğünde bir bildirim nedenini söyler. JSON ya da bir günlük gibi bol tekrarlı metinler bu maliyeti kat kat geri kazanır: sayfanın açılışta gösterdiği örnek, küçük bir JSON, boyutunun yarısından daha küçük çıkar.
Metin olarak yazıldığında baytların maliyeti yine artar. Base64, Base64 aracının kılavuzunun açıkladığı gibi her üç bayt için dört karakter, yani üçte bir fazlasını kullanır; bu yüzden gzip’in o 33 baytı 44 karakter eder; on altılık ise bayt başına iki rakam kullanır ve sayfa bunları boşluklu çiftler hâlinde yazar: aynı 33 bayt için 98 karakter. Boyut satırı bu karakterleri de sayar ve Bayt boyutu dönüştürücü, satırdaki sayıların herhangi birini KB ya da KiB cinsine çevirir.
Sıkıştırmak: düzey yok, gzip -c komutunun baytları değil ve Brotli yok
Sıkıştırma tarayıcının kendi işidir: Compression standardının tanımladığı CompressionStream aracılığıyla yapılır ve bu standart bir sıkıştırma düzeyi sunmaz, dolayısıyla bu sayfa da sunmaz; elde ettiğiniz, tarayıcının varsayılanıdır. gzip -9 biraz daha küçük çıkabilir, ama nadiren çok daha küçük.
Baytlar gzip -c komutunun yazdıkları da değildir, ancak ikisi de açıldığında aynı metni verir. Önce başlıklar farklıdır. GNU gzip, kendisine -n verilmedikçe bir dosyanın adını ve zamanını saklar, bir borudan okurken ise sıfır zaman saklar; başlığın bir baytına -9 ya da -1 düzeyinin kullanıldığını gösteren bir işaret koyar; RFC 1952’nin işletim sistemine ayırdığı onuncu bayta da Linux’ta, Unix’in numarası olan 03 değerini yazar. Tarayıcıya yalnızca baytlar verilir, bu yüzden dosyanızın ne adı ne de zamanı sonuçla birlikte dışarı çıkabilir: Chromium hiçbir ad saklamaz ve sıfır zaman yazar, ki gzip -n komutunun seçtiği de budur; onuncu bayta da Linux’ta 03 yazar, Windows’taki Chrome ise 0a yazar. Ardından sıkıştırılmış veri farklıdır, çünkü GNU gzip’in sıkıştırıcısı tarayıcınınki değildir: uzun bir metinde ikisi aynı düzeyde farklı baytlar seçer. Dolayısıyla gzip -c ile bir uyuşmazlık tek başına hiçbir şey ifade etmez; önemli olan, ikisinin de açıldığında aynı baytları vermesidir.
Brotli şimdilik burada yok. Compression standardı onu adıyla anar, ama henüz her tarayıcı onu yazmıyor ve sayfanın yalnızca tarayıcının onu ürettiği yerde sunabileceği bir seçenek, farklı tarayıcılarda farklı bir sayfa olurdu. zstd ise o standartta hiç yer almaz. Bu sayfanın okuyup yazdığı tek şey, üç sarmalayıcısıyla DEFLATE sıkıştırmasıdır.
İçeri bir dosya, dışarı bir dosya ve hiçbir şey yüklenmez
Her iki yönde de bir dosya metin kutusunun yerini alabilir: bir dosya seçin ya da kutunun üzerine bırakın. Dosyanın baytları olduğu gibi okunur, ne “Sıkıştırılmış veri gösterimi” ne de “Bayt gösterimi” seçicisinden geçer; metin kutusunun bir sınırı varken burada bir dosyanın hiçbir sınırı yoktur, ancak çok büyük bir dosya, tarayıcının onu bellekte tutamayabileceğini söyleyen bir uyarı çıkarır. Sıkıştırmayı açarken “İndir” düğmesi sonucu gunzip’in yaptığı gibi adlandırır: dosyanın adından .gz çıkarılır, .tgz ise .tar olur; aynı şekilde .zz ya da .deflate de çıkarılır, bunlar bu sayfanın öteki iki sarmalayıcı için yazdığı uzantılardır; başka herhangi bir ad ve yapıştırılan her şey bytes.bin olarak çıkar. Sıkıştırırken düğme dosyanın adına .gz, .zz ya da .deflate ekler — .zz, pigz’in zlib için kullandığı uzantıdır — ya da yazdığınız metin için text sözcüğüne ekler.
“Girdi olarak kullan” düğmesi bir sonucu kutuya taşır ve yönü çevirir, böylece gidiş dönüş tek bir tıklama sürer; bir dosyadan gelen ya da kutu için fazla büyük olan bir sonuç ise dosya olarak taşınır. Hangi yönde olursa olsun, dosya bu sekmede okunur ve iş, sayfanın kendi cihazınızda başlattığı bir worker’da yürür: bunun için ne bir yük ne de bir dosya yüklenir.
Aynısı gunzip ve Python ile
Komut satırında gunzip ve zcat, base64 -d bir yükü yeniden baytlara çevirdikten sonra gzip’i bu sayfanın okuduğu gibi, tüm üyeleriyle okur; ancak ikisi de zlib’i ya da ham deflate’i okumaz, ikisini de gzip olmadıkları gerekçesiyle reddeder; gzip -k ise bir dosyayı sıkıştırır ve özgün dosyayı yanında tutar. Python’da gzip.decompress, gzip’in sarmalayıcısını ve içindeki tüm üyeleri okur; zlib.decompress ise üç sarmalayıcıdan herhangi birini okur, hangisi olduğunu da wbits değerinden öğrenir:
# A payload: decode it, then decompress it
printf 'H4sIAAAAAAAAA/NIzcnJ11Eozy/KSVEEAObG5usNAAAA' | base64 -d | gunzip # Hello, world!
# A file: compress it, keeping the original, then print it back
printf 'Hello, world!' > hello.txt
gzip -k hello.txt
zcat hello.txt.gz # Hello, world!
# Two members, the second appended to the first, read back as one
printf 'Hello, ' | gzip > two.gz
printf 'world!' | gzip >> two.gz
zcat two.gz # Hello, world!
# The same in a script: every member, then one wrapper at a time
import base64, gzip, zlib
two = open('two.gz', 'rb').read()
zl = base64.b64decode('eJzzSM3JyddRKM8vyklRBAAgXgSK')
raw = base64.b64decode('80jNycnXUSjPL8pJUQQA')
gzip.decompress(two) # b'Hello, world!'
zlib.decompress(two, wbits=31) # b'Hello, '
zlib.decompress(zl, wbits=15) # b'Hello, world!'
zlib.decompress(raw, wbits=-15) # b'Hello, world!'
zlib.decompress(zl, wbits=47) # b'Hello, world!'wbits değeri 31 olduğunda gzip’in sarmalayıcısı, varsayılan değer olan 15 olduğunda zlib’in sarmalayıcısı, -15 olduğunda ise ham deflate istenir; her birindeki 15, en büyük penceredir. 47 değeri ise baytlar hangisiyle başlıyorsa gzip’inkini ya da zlib’inkini kabul eder. Ancak zlib.decompress tek bir üye okur ve gerisini tek söz söylemeden bırakır; yukarıdaki iki üyeden yalnızca b'Hello, ' değerini geri vermesinin nedeni budur; gzip.decompress ise hepsini okur. Python bu sayfadan iki açıdan daha katıdır: gzip.decompress, sonun ardından gelen ve sıfır olmayan baytları reddeder; iki işlev de erken biten bir akışı reddeder, sayfa ise çıkanı gösterir.
Sıkça sorulan sorular
- Sıkıştırılmış sonucum neden yazdığımdan daha büyük?
- Çünkü her sarmalayıcının kendine ait bir bayt maliyeti vardır ve kısa bir metinde sıkıştırmanın atabileceği pek bir şey yoktur: gzip 18 bayt, zlib 6 bayt ekler, DEFLATE de ayrıca bloklarını işaretler; bu yüzden birkaç sözcük büyürken uzun bir JSON küçülür ve sayfa bunu bir bildirimle söyler. Ham deflate üçünün en küçüğüdür. Base64 olarak yazıldığında her sonuç üçte bir daha uzun olur.
- Çıktı neden gzip -c ile uyuşmuyor?
- Uyuşacağına dair hiçbir güvence yoktur. Bir gzip başlığı bir ad, bir zaman, düzeyi gösteren bir işaret ve işletim sistemi için bir bayt tutabilir; GNU gzip ile tarayıcı bunları farklı doldurur ve ikisi farklı sıkıştırıcılardır, bu yüzden daha uzun bir metinde başlıkla kuyruk arasındaki veri bile farklı olabilir. Aynı metnin iki gzip akışı, her biri açıldığında o metni veriyorsa ikisi de doğrudur; bu yüzden açıldıklarında verdiklerini karşılaştırın: “Girdi olarak kullan” düğmesi bu sayfanın sonucunu hemen geri çevirir.
- Bir yükün başındaki H4sI ne anlama gelir?
- Yükün Base64 olarak yazılmış gzip olduğu anlamına gelir: her gzip akışı 1f 8b 08 baytlarıyla başlar ve bu üç bayt Base64’te H4sI olur. Yükü olduğu gibi buraya yapıştırın. eJ ile başlayan bir yük büyük olasılıkla varsayılan düzeydeki zlib’dir; ikisiyle de başlamayan bir yük ise ham deflate olabilir ya da hiç sıkıştırılmamış olabilir, bunu da sayfa size söyler.
- gzip bir şifreleme mi?
- Hayır. Sıkıştırma hiçbir anahtar kullanmaz; bu yüzden baytları elinde tutan herkes onları burada ya da gunzip ile açabilir ve her bayt geri gelir. gzip ile sıkıştırılmış bir yükün içindeki bir parola, açıkça yazılmış bir parola kadar ortadadır.
- Yüküm ya da dosyam bir yere yükleniyor mu?
- Hayır. Yapıştırdığınız yük de seçtiğiniz ya da bıraktığınız dosya da bu sekmede okunur; sıkıştırmayı da sıkıştırmayı açmayı da sayfanın başlattığı bir worker yapar ve “İndir” düğmesi dosyasını sonuçtan orada oluşturur. İkisi de ne bu siteye ne de başka birine gönderilir.
İlgili araçlar
- JSON biçimlendirici
JSON’u doğrulayın ve güzelleştirin, hata konumları net.
- Bayt boyutu dönüştürücü
KB, MB, GB ile KiB, MiB, GiB arasında dönüştürün.
- Base64
Base64 kodlayın ve çözün — tam UTF-8 desteği.
- Base32
Base32 ve base32hex kodlayın ve çözün — UTF-8 metin ya da on altılık baytlar.