modified | Thursday 1 May 2025 |
---|
6.6 “ 使 用 ZLib 进 行 压 缩 / 解
庄 绢
ZLib 模 块 为 我 们 提 供 了 压 缩 / 解 压 缩
的 功 能 。 它 也 是 基 于 转 换 流 的 , 当 你
看 到 Node 文 档 中 关 于 压 缩 文 件 的 例 子
时 , 就 会 明 白 了 。 我 会 对 示 例 稍 作 修
改 , 从 而 可 以 操 作 大 文 件 。
var zlib = require( 「Zz1Lib 「 ) ;
var fs = require( 「 fs 「) ;
var gzip = z1Lib,createGzip( ) ;
var inp =
fs. createReadStream( 「test png 「 ) }
var out =
fs, createWriteStream(「test.png,g9z 「 ) }
inp,pipe(gzip) ,pipe(out) ;
493 1 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 缩
输 入 流 跟 输 出 流 通 过 中 间 的 gzip 压 缩
器 直 接 连 接 起 来 , 进 行 内 容 转 换 一 一
在 本 例 中 压 缩 的 是 PNG 文 件 。
Zlib 为 我 们 使 用 zlib 或 deflate 压 缩 提 供
了 支 持 ,deflate 是 一 个 更 加 复 杂 、 可
控 的 压 缩 算 法 。 要 注 意 ,deflate 和
zlib 不 一 样 , 在 zlib 中 可 以 用 gunzip
( 或 unzip) 命 令 来 解 压 文 件 , 在
deflate 中 却 不 能 这 样 做 。 你 必 须 使 用
Node 或 一 些 其 他 功 能 来 解 压 缩 用
deflate 压 缩 的 文 件 。
为 了 演 示 压 缩 文 件 和 解 压 文 件 这 两 个
功 能 , 我 们 创 建 两 个 命 令 行 工 具 :
compress 和 uncompress。 第 一 个 工
具 会 使 用 gzip 或 deflate 其 中 一 个 来 压
缩 文 件 。 由 于 有 不 同 的 参 数 , 所 以 还
会 使 用 Commander 模 块 来 处 理 命 令
494 1 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 缩
行 参 数
var zLib = require( ˇzlib「) ;
var program = require(「 commander 「) }
var fs = require( “fs 「 ) }
program
,version (“8.804.1“)
.0ption (「 -S,–5S0ource [fiLe
name] “ , 「Source FiLe Name 「)
.option (「“-f,–file [file
name] “ , “「Destination FiLe name )
.0ption (「-t ,–type
^(gzip|deflate) $/ 1)
.parse(procesSs.argv) ;
var compress ;
if (〔program.type == ,dqefLate 「 )
compress = z1ib. createDefLate ( ) ;
elLse
compress = z1Lib. createGzip( ) ;
var inp =
fs.createReadstream(program, source) }
Var 0ut =
fs. createWriteStream(program.,fiLe) ;
inp.pipe(compress) ,pipe(out) }
495 1 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 缩
这 是 一 个 既 有 意 思 叉 很 好 用 的 工 具 程
序 ( 尤 其 在 Windows 环 境 中 , 因 为
Windows 系 统 原 生 不 支 持 这 种 类 型 的
压 缩 功 能 ) , 但 压 缩 技 术 更 广 泛 的 使
用 场 景 却 是 在 Web 请 求 中 〔(We b
request) 。Node 文 档 中 包 含 了 一 些
使 用 Zlib 来 处 理 Web 请 求 的 例 子 。 同
时 也 有 一 些 使 用 Request 模 块 和
http.request() 园 数 获 取 压 缩 文 件 的 例
子 ( 在 第 5 章 中 介 绍 过 ) 。
这 里 我 们 不 演 示 如 何 下 载 压 缩 文 件 ,
而 是 演 示 如 何 将 庄 缩 后 的 文 件 上 传 到
服 务 器 , 然 后 在 服 务 器 端 将 其 解 压 。
我 会 调 整 例 5-1 和 例 5-2 中 的 服 务 器 和
客 户 端 应 用 程 序 , 修 改 代 码 以 压 缩 大
型 PNG 文 件 , 并 通 过 HTTP 请 求 发 送
压 缩 后 的 文 件 , 然 后 让 服 务 器 解 压 并
保 存 文 件 。
496 1 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 缉
服 务 器 端 的 代 码 如 例 6-5 所 示 。 需 要
注 意 的 是 , 发 送 的 数 据 会 以 数 据 块 数
组 的 格 式 被 接 收 , 最 后 使 用
buffer.concat() 来 合 成 一 个 新 的 缓 冲
器 。 因 为 这 里 处 理 的 是 一 个 缓 冲 器 而
不 是 一 个 流 , 所 以 不 能 使 用 pipel() 出
数 。 不 过 , 我 会 使 用 zlib 中 一 个 很 便
捷 的 团 数 zlib.unzip, 需 要 给 人 传 入 缓
冰 器 和 一 个 回 调 闻 数 。 回 调 出 数 具 有
两 个 参 数 一 一 error 和 result。 这 里 的
result 也 是 一 个 缓 冲 器 , 宁 会 被
write() 国 数 写 入 一 个 新 创 建 的 可 写
流 。 为 了 确 保 同 名 文 件 不 会 被 覆 盖 ,
我 给 文 件 名 加 上 了 时 间 戬 。
例 6-5 创 建 一 个 Web 服 务 器 来 接 收
庄 缩 后 的 数 据 并 将 其 解 压 到 一 个 文 件
中
497/ 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 缩
var http = require( http 「 ) }
var zLib = require( 「z1Lib 「) }
var fs = require( “fs 「 ) }
var sServer =
http, createServer( ) , Listen(8124) ;
server,on( 「 request 「 ,
function( request, response) t
if (request.method == ,P0ST「 ) {
var cChunks = “[] ;
request.on(「data 1 ,
function(chunk) t
chunks,push(chunk) ;
) ;
request.on( 「end 「 , function() t
vVar buf =
Buffer. concat (chunks) ;
Zz1Lib,unzip(buf ,
function(err, resuLt)〗 t
if (err) t
response.writeHead (500) ;
response,end ( ) }
return
consolte, tog( 「error , + err) }
]
var imestamp =
498 / 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 缩
Date. now( ) ;
var fiLename = , /done 「
了 ) ;
requon( 「error,「 ,function(e) t
consolte, Log( “probtem with request:
“,+ e,message) }
了 ) ;
/ stream gzipped filte to server
var readable =
fs. createReadStream( “ ./test , png 「 ) }
readable..pipe(gzip) .pipe( req) ;
客 户 端 打 开 要 压 缩 的 文 件 , 然 后 将 其
传 入 Zlib 压 缩 转 换 流 , 压 缩 后 的 结 果
被 传 入 Web 请 求 ( 一 个 可 与 流 ) 。 因
为 在 这 段 代 码 中 我 们 只 是 处 理 流 , 所
以 可 以 使 用 之 前 用 过 的 pipe() 功 能 。
但 不 能 在 服 务 器 中 使 用 管 道 , 因 为 在
服 务 器 中 数 据 将 以 缓 存 块 的 形 式 传
输 。
在 内 存 中 缓 存 文 件 可 能 导 致 性 能 问
5011 833
6.6 使 用 ZLib 进 行 压 缩 / 解 压 编
题 , 所 以 另 一 种 方 式 是 保 存 压 缉 文
件 , 解 压 毛 , 然 后 删 除 那 个 临 时 的 压
缩 文 件 。 这 个 就 作 为 读 者 课 后 的 练 习
吧 。
502 1 833