Node.js实战--资源压缩与zlib模块

2019/04/10 10:10
阅读数 19

<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="font-size: 16px; color: black; padding: 10px; line-height: 1.6; word-spacing: 0px; letter-spacing: 0px; word-break: break-word; word-wrap: break-word; text-align: left; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px;"><img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbaz8apugbj315d0lqt9u.jpg" alt style="display: block; margin: 0 auto; width: 100%;"></figure> <blockquote data-tool="mdnice编辑器" style="display: block; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; border-left: 3px solid rgba(0, 0, 0, 0.4); background: rgba(0, 0, 0, 0.05); padding-top: 10px; padding-bottom: 10px; border-left-color: rgb(221, 221, 221); margin-top: 1.2em; margin-bottom: 1.2em; padding-right: 1em; padding-left: 1em; border-left-width: 4px; color: rgb(119, 119, 119); quotes: none;"> <p style="padding-top: 8px; padding-bottom: 8px; box-sizing: border-box; margin-bottom: 16px; text-align: start; white-space: normal; text-size-adjust: auto; margin: 0px; font-size: 15px; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; color: rgb(119, 119, 119); line-height: 1.75em;"><strong style="font-weight: bold; color: black;">📖Blog:<a href="https://xxoo521.com/2020-01-26-zlib/" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">《NodeJS模块研究 - zlib》</a></strong></p> <p style="padding-top: 8px; padding-bottom: 8px; box-sizing: border-box; margin-bottom: 16px; text-align: start; white-space: normal; text-size-adjust: auto; margin: 0px; font-size: 15px; font-family: -apple-system-font, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei UI', 'Microsoft YaHei', Arial, sans-serif; color: rgb(119, 119, 119); line-height: 1.75em;"><strong style="font-weight: bold; color: black;">🐱Github:<a href="https://github.com/dongyuanxin/blog" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">https://github.com/dongyuanxin/blog</a></strong></p> </blockquote> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">nodejs 的 zlib 模块提供了资源压缩功能。例如在 http 传输过程中常用的 gzip,能大幅度减少网络传输流量,提高速度。本文将从下面几个方面介绍 zlib 模块和相关知识点:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">文件压缩 / 解压</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">HTTP 中的压缩/解压</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">压缩算法:RLE</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">压缩算法:哈夫曼树</section></li></ul> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">文件的压缩/解压</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">以 gzip 压缩为例,压缩代码如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> zlib = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"zlib"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> gzip = zlib.createGzip();

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> rs = fs.createReadStream(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./db.json"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> ws = fs.createWriteStream(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./db.json.gz"</span>); rs.pipe(gzip).pipe(ws); </code></pre>

<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">如下图所示,4.7Mb 大小的文件被压缩到了 575Kb。</p> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px;"><img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbaxr9d139j30q802eq3d.jpg" alt style="display: block; margin: 0 auto; width: 100%;"></figure> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">解压刚才压缩后的文件,代码如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> zlib = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"zlib"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> gunzip = zlib.createGunzip();

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> rs = fs.createReadStream(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./db.json.gz"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> ws = fs.createWriteStream(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./db.json"</span>); rs.pipe(gunzip).pipe(ws); </code></pre>

<h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">HTTP 中的压缩/解压</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">在服务器中和客户端的传输过程中,浏览器(客户端)通过 Accept-Encoding 消息头来告诉服务端接受的压缩编码,服务器通过 Content-Encoding 消息头来告诉浏览器(客户端)实际用于编码的算法。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">服务器代码示例如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> zlib = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"zlib"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> http = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"http"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> server = http.createServer(<span class="hljs-function" style="line-height: 26px;">(<span class="hljs-params" style="line-height: 26px;">req, res</span>) =></span> { <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> rs = fs.createReadStream(<span class="hljs-string" style="color: #d14; line-height: 26px;">"./index.html"</span>); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 防止缓存错乱</span> res.setHeader(<span class="hljs-string" style="color: #d14; line-height: 26px;">"Vary"</span>, <span class="hljs-string" style="color: #d14; line-height: 26px;">"Accept-Encoding"</span>); <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 获取客户端支持的编码</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">let</span> acceptEncoding = req.headers[<span class="hljs-string" style="color: #d14; line-height: 26px;">"accept-encoding"</span>]; <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (!acceptEncoding) { acceptEncoding = <span class="hljs-string" style="color: #d14; line-height: 26px;">""</span>; } <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 匹配支持的压缩格式</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (<span class="hljs-regexp" style="color: #009926; line-height: 26px;">/\bdeflate\b/</span>.test(acceptEncoding)) { res.writeHead(<span class="hljs-number" style="color: #008080; line-height: 26px;">200</span>, { <span class="hljs-string" style="color: #d14; line-height: 26px;">"Content-Encoding"</span>: <span class="hljs-string" style="color: #d14; line-height: 26px;">"deflate"</span> }); rs.pipe(zlib.createDeflate()).pipe(res); } <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">else</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (<span class="hljs-regexp" style="color: #009926; line-height: 26px;">/\bgzip\b/</span>.test(acceptEncoding)) { res.writeHead(<span class="hljs-number" style="color: #008080; line-height: 26px;">200</span>, { <span class="hljs-string" style="color: #d14; line-height: 26px;">"Content-Encoding"</span>: <span class="hljs-string" style="color: #d14; line-height: 26px;">"gzip"</span> }); rs.pipe(zlib.createGzip()).pipe(res); } <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">else</span> <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">if</span> (<span class="hljs-regexp" style="color: #009926; line-height: 26px;">/\bbr\b/</span>.test(acceptEncoding)) { res.writeHead(<span class="hljs-number" style="color: #008080; line-height: 26px;">200</span>, { <span class="hljs-string" style="color: #d14; line-height: 26px;">"Content-Encoding"</span>: <span class="hljs-string" style="color: #d14; line-height: 26px;">"br"</span> }); rs.pipe(zlib.createBrotliCompress()).pipe(res); } <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">else</span> { res.writeHead(<span class="hljs-number" style="color: #008080; line-height: 26px;">200</span>, {}); rs.pipe(res); } });

server.listen(<span class="hljs-number" style="color: #008080; line-height: 26px;">4000</span>); </code></pre>

<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">客户端代码就很简单了,识别 Accept-Encoding 字段,并进行解压:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px;"><code class="hljs" style="overflow-x: auto; padding: 16px; color: #333; background: #f8f8f8; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; border-radius: 0px; font-size: 12px; -webkit-overflow-scrolling: touch;"><span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> zlib = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"zlib"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> http = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"http"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> fs = <span class="hljs-built_in" style="color: #0086b3; line-height: 26px;">require</span>(<span class="hljs-string" style="color: #d14; line-height: 26px;">"fs"</span>); <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> request = http.get({ <span class="hljs-attr" style="line-height: 26px;">host</span>: <span class="hljs-string" style="color: #d14; line-height: 26px;">"localhost"</span>, <span class="hljs-attr" style="line-height: 26px;">path</span>: <span class="hljs-string" style="color: #d14; line-height: 26px;">"/index.html"</span>, <span class="hljs-attr" style="line-height: 26px;">port</span>: <span class="hljs-number" style="color: #008080; line-height: 26px;">4000</span>, <span class="hljs-attr" style="line-height: 26px;">headers</span>: { <span class="hljs-string" style="color: #d14; line-height: 26px;">"Accept-Encoding"</span>: <span class="hljs-string" style="color: #d14; line-height: 26px;">"br,gzip,deflate"</span> } }); request.on(<span class="hljs-string" style="color: #d14; line-height: 26px;">"response"</span>, response =&gt; { <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">const</span> output = fs.createWriteStream(<span class="hljs-string" style="color: #d14; line-height: 26px;">"example.com_index.html"</span>);

<span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">switch</span> (response.headers[<span class="hljs-string" style="color: #d14; line-height: 26px;">"content-encoding"</span>]) {
    <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">case</span> <span class="hljs-string" style="color: #d14; line-height: 26px;">"br"</span>:
        response.pipe(zlib.createBrotliDecompress()).pipe(output);
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
    <span class="hljs-comment" style="color: #998; font-style: italic; line-height: 26px;">// 或者, 只是使用 zlib.createUnzip() 方法去处理这两种情况:</span>
    <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">case</span> <span class="hljs-string" style="color: #d14; line-height: 26px;">"gzip"</span>:
        response.pipe(zlib.createGunzip()).pipe(output);
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
    <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">case</span> <span class="hljs-string" style="color: #d14; line-height: 26px;">"deflate"</span>:
        response.pipe(zlib.createInflate()).pipe(output);
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
    <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">default</span>:
        response.pipe(output);
        <span class="hljs-keyword" style="color: #333; font-weight: bold; line-height: 26px;">break</span>;
}

}); </code></pre>

<p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">从上面的例子可以看出来,3 种对应的解压/压缩 API:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">zlib.createInflate()</code> 和 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">zlib.createDeflate()</code></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">zlib.createGunzip()</code> 和 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">zlib.createGzip()</code></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">zlib.createBrotliDecompress()</code> 和 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">zlib.createBrotliCompress()</code></section></li></ul> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">压缩算法:RLE</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">RLE 全称是 Run Length Encoding, 行程长度编码,也称为游程编码。它的原理是:记录连续重复数据的出现次数。它的公式是:<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">字符 * 出现次数</code>。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">例如原数据是 <code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">AAAAACCPPPPPPPPERRPPP</code>,一共 18 个字节。按照 RLE 的规则,压缩后的结果是:<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">A5C2P8E1R2P3</code>,一共 12 个字节。压缩比例是:12 / 17 = 70.6%</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">RLE 的优点是压缩和解压非常快,针对连续出现的多个字符的数据压缩率更高。但对于<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">ABCDE</code>类似的数据,压缩后数据会更大。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">压缩算法:哈夫曼树</span></h2> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">哈夫曼树的原理是:出现频率越高的字符,用尽量更少的编码来表示。按照这个原理,以数据<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">ABBCCCDDDD</code>为例:</p> <table data-tool="mdnice编辑器" style="display: table; text-align: left;"> <thead> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <th style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-weight: bold; background-color: #f0f0f0;">字符</th> <th style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-weight: bold; background-color: #f0f0f0;">编码(二进制)</th> </tr> </thead> <tbody style="border: 0;"> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">D</td> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">0</td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;"> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">C</td> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">1</td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">B</td> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">10</td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;"> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">A</td> <td style="font-size: 16px; border: 1px solid #ccc; padding: 5px 10px; text-align: left;">11</td> </tr> </tbody> </table> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">原来的数据是 10 个字节。那么编码后的数据是:<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">1110101110000</code>,一共 13bit,在计算机中需要 2 个字节来存储。这样的压缩率是:2 / 10 = 20%。</p> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">但是仅仅按照这个原理编码后的数据,无法正确还原。以前 4bit 为例,<code style="font-size: 14px; word-wrap: break-word; padding: 2px 4px; border-radius: 4px; margin: 0 2px; background-color: rgba(27,31,35,.05); font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; word-break: break-all; color: rgb(239, 112, 96);">1110</code>可以理解成:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">11 + 10</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">1 + 1 + 1 + 0</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">1 + 1 + 10</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;">...</section></li></ul> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">而哈夫曼树的设计就很巧妙,能正确还原。哈夫曼树的构造过程如下:</p> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px;"><img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbb0eessplj30u00us1kx.jpg" alt style="display: block; margin: 0 auto; width: 100%;"></figure> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">无论哪种数据类型(文本文件、图像文件、EXE 文件),都可以采用哈夫曼树进行压缩。</p> <h2 data-tool="mdnice编辑器" style="margin-top: 40px; margin-bottom: 20px; font-weight: bold; color: black; font-size: 24px; margin: 10px auto; height: 40px; background-color: rgb(251, 251, 251); border-bottom: 1px solid rgb(246, 246, 246); overflow: hidden; box-sizing: border-box;"><span style="margin-left: -10px; display: inline-block; width: auto; height: 40px; background-color: rgb(33, 33, 34); border-bottom-right-radius: 100px; color: rgb(255, 255, 255); padding-right: 30px; padding-left: 30px; line-height: 40px; font-size: 16px;">参考链接</span></h2> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="http://nodejs.cn/api/zlib.html" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">Nodejs 文档</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://zhuanlan.zhihu.com/p/47049060" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">30 分钟 HTTP 查漏补缺之 Vary</a></section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500; font-size: 15px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif;"><a href="https://juejin.im/post/5e1e8ca2f265da3e11359d2a" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">程序员不得不了解的硬核知识大全</a></section></li></ul> <img src="https://tva1.sinaimg.cn/large/006tNbRwly1gbjcfr3xb5j30cw00tjrd.jpg" style="display: block; margin: 0 auto; width: 100% !important;" data-tool="mdnice编辑器"> <p data-tool="mdnice编辑器" style="padding-top: 8px; padding-bottom: 8px; margin: 0; color: black; box-sizing: border-box; margin-bottom: 16px; font-family: 'Helvetica Neue', Helvetica, 'Segoe UI', Arial, freesans, sans-serif; font-size: 15px; text-align: start; white-space: normal; text-size-adjust: auto; line-height: 1.75em;">👇<strong style="font-weight: bold; color: black;">扫码关注<a href="https://tva1.sinaimg.cn/large/006tNbRwly1g9xhhp50jpj31bi0hcju4.jpg" style="text-decoration: none; word-wrap: break-word; font-weight: bold; color: rgb(239, 112, 96); border-bottom: 1px solid rgb(239, 112, 96);">「心谭博客」</a>,查看「前端图谱」&amp;「算法题解」,坚持分享,共同成长</strong>👇</p> <figure data-tool="mdnice编辑器" style="margin: 0; margin-top: 10px; margin-bottom: 10px;"><img src="https://tva1.sinaimg.cn/large/006tNbRwly1g9xhhp50jpj31bi0hcju4.jpg" alt style="display: block; margin: 0 auto; width: 100%;"></figure> </section>

原文出处:https://www.cnblogs.com/geyouneihan/p/12296740.html

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部