【jszip】压缩/解压缩文件

5,314 阅读4分钟

先上官方文档: stuk.github.io/jszip/

jszip在浏览器端的基本操作

解压文件

AJAX request

用ajax请求获取二进制数据是困难的(主要是因为IE <= 9),简单的方法是使用JSZipUtils.getBinaryContent。

  • 安装 jszip-utils npm i jszip-utils
  • 在html中引用:
<script type="text/javascript" src="dist/jszip-utils.js"></script>

<!--Mandatory in IE 6, 7, 8 and 9.-->
<!--[if IE]>
<script type="text/javascript" src="dist/jszip-utils-ie.js"></script>
<![endif]-->
  • 在 js 文件中引用 var JSZipUtils = require('jszip-utils');
  • 调用过程
JSZipUtils.getBinaryContent('path/to/content.zip', function(err, data) {
    if(err) {
        throw err; // or handle err
    }

    JSZip.loadAsync(data).then(function () {
        // ...
    });
});


// or, with promises:

new JSZip.external.Promise(function (resolve, reject) {
    JSZipUtils.getBinaryContent('path/to/content.zip', function(err, data) {
        if (err) {
            reject(err);
        } else {
            resolve(data);
        }
    });
}).then(function (data) {
    return JSZip.loadAsync(data);
})
.then(...)

本地文件

首先,你所用的浏览器需要支持 FileReader API,那么你就可以通过 FileReader API 来读取本地文件啦,

image.png

<input type="file" id="file" name="file" multiple 
onchange={(evt)=>{
 var files = evt.target.files;
    for (var i = 0; i < files.length; i++) {
        JSZip.loadAsync(f).then(function(zip) {
    
        // 读取成功,zip为压缩文件内容对象
        doSomethingWithSuccess(zip);
        
        }, function (e) {
        
        // 可能由于文件类型不匹配等原因读取失败
        doSomethingWithError(e);
        
        });
        }
    }
}/>

压缩文件

由于只有javascript,这部分不能在旧浏览器中工作,包括IE < 10。对于其他浏览器,可以采用下面的方法生成压缩文件并存储在本地,由于浏览器无法直接读写本地文件,所以通过浏览器下载的方式存储至本地。

FileSaver API

适用于firefox, chrome, opera >= 15和IE >= 10(但不是在兼容性视图)。在较新的浏览器中最简单的方法是使用saveAs或polyfill,参见FileSaver.js,一些旧的浏览器兼容方式在 FileSaver 的 Readme 中有写,有需要的小伙伴可以详细研究一下,我在这里就不多说了。 下面这里引用了两段 FileSaver 的 Readme ,来介绍 FileSaver 的适用范围。

如果你需要保存比blob的大小限制更大的文件,或者没有足够的RAM,那么可以看看更高级的StreamSaver.js,它可以使用新的流API将数据直接异步保存到硬盘驱动器。这将支持进度,取消,并知道何时完成。

FileSaver.js保存文件在客户端,很适合web应用程序在客户端生成文件,但是如果文件来自服务器,我们建议您先尝试使用附加附件响应头,因为它有更多的跨浏览器相容性。

import { saveAs } from 'file-saver';
let JSZip = require('jszip');

var zip = new JSZip();
zip.file("Hello.txt", "Hello world\n");
zip.generateAsync({type:"blob"}).then(function (blob) {     // 1) generate the zip file
        saveAs(blob, "hello.zip");                          // 2) trigger the download
    }, function (err) {
        doSomethingWithError(e);
    });

Data URL

在IE中不工作,对长度有限制。

image.png

var zip = new JSZip();
zip.file("Hello.txt", "Hello world\n");
 zip.generateAsync({type:"base64"}).then(function (base64) {          // 1) generate the zip file
        window.location = "data:application/zip;base64," + base64;    // 2) trigger the download
    }, function (err) {
        doSomethingWithError(e);
    });

(○´・д・)ノ注意

这里最大的问题是文件名非常别扭,Firefox会生成像a5sZQRsx.zip.part这样的文件名。

image.png

Downloadify

Downloadify使用一个小的Flash SWF(SWF 文件是使用Flash软件生成的常见文件,会用于PPT插入等操作)来下载文件到用户的电脑,文件的文件名你可以选择。Doug Neiner添加了dataType选项,允许您通过zip文件进行下载。

swf仅供在线使用。从文件路径(即文件://)进行测试将不起作用,因为它将违反安全沙箱。

zip = new JSZip();
zip.file("Hello.", "hello.txt");

zip.generateAsync({type:"base64"}).then(function (base64) {
    Downloadify.create('downloadify',{
    ...
    data: function(){
        return base64;
    },
    ...
    dataType: 'base64'
    });
});

jszip在 nodejs 的基本操作

解压文件

本地文件

JSZip can read Buffers so you can do the following :

"use strict";

var fs = require("fs");
var JSZip = require("jszip");

// read a zip file
fs.readFile("test.zip", function(err, data) {
    if (err) throw err;
    JSZip.loadAsync(data).then(function (zip) {
        // ...
    });
});

// or
new JSZip.external.Promise(function (resolve, reject) {
    fs.readFile("test.zip", function(err, data) {
        if (err) {
            reject(e);
        } else {
            resolve(data);
        }
    });
}).then(function (data) {
    return JSZip.loadAsync(data);
})
.then(...)

远端文件

有很多nodejs库执行http请求,从内置的http到npm包。这里有三个示例,一个使用默认的http API,另一个使用request,另一个使用axios。如果可能的话,将文件下载为Buffer(您将获得更好的性能)

With http :
"use strict";

var http = require("http");
var url = require("url");
var JSZip = require("jszip");

var req = http.get(url.parse("http://localhost/.../file.zip"), function (res) {
  if (res.statusCode !== 200) {
    console.log(res.statusCode);
    // handle error
    return;
  }
  var data = [], dataLen = 0;

  // don't set the encoding, it will break everything !
  // or, if you must, set it to null. In that case the chunk will be a string.

  res.on("data", function (chunk) {
    data.push(chunk);
    dataLen += chunk.length;
  });

  res.on("end", function () {
    var buf = Buffer.concat(data);

    // here we go !
    JSZip.loadAsync(buf).then(function (zip) {
      return zip.file("content.txt").async("string");
    }).then(function (text) {
      console.log(text);
    });
  });
});

req.on("error", function(err){
  // handle error
});
With request :
"use strict";

var request = require('request');
var JSZip = require("jszip");

request({
  method : "GET",
  url : "http://localhost/.../file.zip",
  encoding: null // <- this one is important !
}, function (error, response, body) {
  if(error ||  response.statusCode !== 200) {
    // handle error
    return;
  }
  JSZip.loadAsync(body).then(function (zip) {
    return zip.file("content.txt").async("string");
  }).then(function (text) {
    console.log(text);
  });
});
With axios
import axios from 'axios';
var JSZip = require("jszip");

 axios.get(filePath, { responseType: 'arraybuffer' })
        .then((response) => {
         JSZip.loadAsync(response.data).then(function (zip) {
            return zip.file("content.txt").async("string");
          }).then(function (text) {
            console.log(text);
          });
        })
        .catch((error: any) => {
          console.error(`download file error:${error}`);
        });

读取出来的内容解析

JSZip.loadAsync(data).then(function (zip) {
    // 文本格式的文件
     zip.file("content.txt").async("string").then((content)=>{...});
    // png jpg pdf 
    zip.file("content.txt").async('uint8array').then((content)=>{...});
}).then(function (text) {
     console.log(text);
});

压缩文件

读取文件并添加至zip文件中

// read a file and add it to a zip
fs.readFile("picture.png", function(err, data) {
    if (err) throw err;
    var zip = new JSZip();
    zip.file("picture.png", data);
});

// or
var contentPromise = new JSZip.external.Promise(function (resolve, reject) {
    fs.readFile("picture.png", function(err, data) {
        if (err) {
            reject(e);
        } else {
            resolve(data);
        }
    });
});
zip.file("picture.png", contentPromise);

// read a file as a stream and add it to a zip
var stream = fs.createReadStream("picture.png");
zip.file("picture.png", stream);

将zip内容制成压缩包

JSZip can generate Buffers so you can do the following :

var fs = require("fs");
var JSZip = require("jszip");

var zip = new JSZip();
// zip.file("file", content);
// ... and other manipulations

zip
.generateNodeStream({type:'nodebuffer',streamFiles:true})
.pipe(fs.createWriteStream('out.zip'))
.on('finish', function () {
    // JSZip generates a readable stream with a "end" event,
    // but is piped here in a writable stream which emits a "finish" event.
    console.log("out.zip written.");
});
var fs = require("fs");
var JSZip = require("jszip");

var zip = new JSZip();
// zip.file("file", content);
// ... and other manipulations

const zipContent = await zip.generateAsync({
      //设置压缩格式,开始打包
      type: 'nodebuffer', //nodejs用
      compression: 'STORE', //压缩算法
    });
fs.writeFileSync(targetPath, zipContent);

后语

有人常说,人生就是一场不停取舍和选择的比赛,有人用健康换金钱,也有人用金钱换健康,有人牺牲当下换取未来的安稳,有人放弃了感情选择了半生的依靠,有人为了成功选择践踏别人的努力。我们总以为这就是通往幸福的最佳路径,但错过了或许一生只能看见一次的沿途风景。别走得太远就忘了当时为什么出发了,别跑的太快就在无数的岔路口中迷失了自己。 ——《我在他乡挺好的》