Thư viện chuẩn
Gzip
zlib.gzip/unzip (promisify) của Node.js so với compress/gzip (Go), flate2 (Rust), zlib qua C interop (Swift) và java.util.zip (Java).
- Phiên bản tối thiểu
- Node.js ≥ 14.13.1Go ≥ 1.0Rust ≥ 1.67Swift ≥ 4.0Java ≥ 25
- Đã chạy thử trên
- Node.js 24.12.0Go 1.27.1Rust 1.98.1Swift 6.2.4Java 25.0.4.1
Code Node.js là ES module: lưu file .mjs hoặc đặt "type": "module" trong package.json.
Node.js expose gzip qua callback trong node:zlib, nên ví dụ dưới dùng promisify để await được. Go làm việc trực tiếp với io.Writer/io.Reader: gzip.NewWriter bọc quanh một buffer để nén, gzip.NewReader đọc ngược lại để giải nén. Rust không có gzip trong std nên dùng crate flate2, cũng theo mô hình Read/Write. Swift không có API gzip nào ở tầng Foundation lẫn framework Compression (framework đó chỉ nén ra định dạng zlib/LZFSE, không phải container gzip thật) — ví dụ dưới gọi thẳng zlib của hệ thống qua C interop (import zlib). Java dùng java.util.zip.GZIPOutputStream/GZIPInputStream có sẵn từ rất lâu.
Nén và giải nén
import { gzip, unzip } from 'node:zlib'
import { promisify } from 'node:util'
const gzipAsync = promisify(gzip)
const unzipAsync = promisify(unzip)
const data = Buffer.from('hello world', 'utf-8')
const compressed = await gzipAsync(data)
console.log(compressed) // <Buffer 1f 8b 08 00 ...>
const decompressed = await unzipAsync(compressed)
console.log(decompressed.toString()) // hello worldpackage main
import (
"bytes"
"compress/gzip"
"fmt"
)
func main() {
data := []byte("hello world")
compressed := new(bytes.Buffer)
w := gzip.NewWriter(compressed)
if _, err := w.Write(data); err != nil {
panic(err)
}
if err := w.Close(); err != nil { // bắt buộc Close để flush hết dữ liệu nén
panic(err)
}
fmt.Println(compressed.Bytes()) // [31 139 8 0 ...]
decompressed := new(bytes.Buffer)
r, err := gzip.NewReader(compressed)
if err != nil {
panic(err)
}
if _, err := decompressed.ReadFrom(r); err != nil {
panic(err)
}
fmt.Println(string(decompressed.Bytes())) // hello world
}// Cargo.toml: flate2 = "1"
use std::io::{Read, Write};
use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
use flate2::Compression;
fn main() {
let data = b"hello world";
let mut encoder = GzEncoder::new(Vec::new(), Compression::default());
encoder.write_all(data).unwrap();
let compressed = encoder.finish().unwrap(); // bắt buộc finish() để flush hết dữ liệu nén
println!("{compressed:?}");
let mut decoder = GzDecoder::new(&compressed[..]);
let mut decompressed = String::new();
decoder.read_to_string(&mut decompressed).unwrap();
println!("{decompressed}");
}import zlib
func gzipCompress(_ input: [UInt8]) -> [UInt8] {
var stream = z_stream()
// windowBits 31 = 15 (kích thước window mặc định) + 16 (chọn container gzip thay vì zlib)
deflateInit2_(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY,
ZLIB_VERSION, Int32(MemoryLayout<z_stream>.size))
defer { deflateEnd(&stream) }
var output = [UInt8](repeating: 0, count: input.count + 64)
var mutableInput = input
let written: Int = mutableInput.withUnsafeMutableBufferPointer { inBuf in
output.withUnsafeMutableBufferPointer { outBuf in
stream.next_in = inBuf.baseAddress
stream.avail_in = UInt32(inBuf.count)
stream.next_out = outBuf.baseAddress
stream.avail_out = UInt32(outBuf.count)
deflate(&stream, Z_FINISH)
return outBuf.count - Int(stream.avail_out)
}
}
return Array(output.prefix(written))
}
func gunzipDecompress(_ input: [UInt8], expectedSize: Int) -> [UInt8] {
var stream = z_stream()
inflateInit2_(&stream, 31, ZLIB_VERSION, Int32(MemoryLayout<z_stream>.size)) // 31: chỉ chấp nhận container gzip
defer { inflateEnd(&stream) }
var output = [UInt8](repeating: 0, count: expectedSize)
var mutableInput = input
let written: Int = mutableInput.withUnsafeMutableBufferPointer { inBuf in
output.withUnsafeMutableBufferPointer { outBuf in
stream.next_in = inBuf.baseAddress
stream.avail_in = UInt32(inBuf.count)
stream.next_out = outBuf.baseAddress
stream.avail_out = UInt32(outBuf.count)
inflate(&stream, Z_FINISH)
return outBuf.count - Int(stream.avail_out)
}
}
return Array(output.prefix(written))
}
let data = Array("hello world".utf8)
let compressed = gzipCompress(data)
print(compressed)
let decompressed = gunzipDecompress(compressed, expectedSize: data.count)
print(String(decoding: decompressed, as: UTF8.self)) // hello worldvoid main() throws Exception {
byte[] data = "hello world".getBytes();
ByteArrayOutputStream compressed = new ByteArrayOutputStream();
try (GZIPOutputStream gzip = new GZIPOutputStream(compressed)) {
gzip.write(data);
} // try-with-resources tự close() để flush hết dữ liệu nén
byte[] compressedBytes = compressed.toByteArray();
int[] unsignedBytes = new int[compressedBytes.length];
for (int i = 0; i < compressedBytes.length; i++) {
unsignedBytes[i] = compressedBytes[i] & 0xff; // byte của Java có dấu; & 0xff để in giá trị 0-255 như các ngôn ngữ khác
}
IO.println(Arrays.toString(unsignedBytes));
try (GZIPInputStream gunzip = new GZIPInputStream(new ByteArrayInputStream(compressedBytes))) {
IO.println(new String(gunzip.readAllBytes())); // hello world
}
}Tham khảo: github.com/miguelmota/golang-for-nodejs-developers#gzip