日期:2014-05-16  浏览次数:20577 次

javascript生成zip编码问题

jsZip ? 一个接口很明确的用 javascript 生成 zip 文件的库,它利用了标准浏览器的 data 协议 可以使得 javascript 生成的内容由用户保存到本地文件,但是由于作者主要处于英文环境下,对于其他语言文字比如中文考虑不太周全,可以在其首页实验一下中文文件名称和中文内容。

(firefox,safari可用, 注意下载文件须手动修改后缀名为 zip )

?

分析其实现:

利用 javascript 中单个字符表示其他程序语言中的 byte 概念,zip格式的二进制控制字符以及整数通过\xyy编码到javascript字符串中,再利用base64编码对每三个字符所表示的二进制byte(charCode)编码为4个 base64编码


整数编码到字符串(字符数组 == byte数组)

原始代码用 eval 封装 byte 到字符,比较难看,我修改为 String.fromCharCode

?

JSZip.prototype.decToHex = function(dec, bytes)
{
   var hex = "";
	for(var i=0;i<bytes;i++) {
		hex+=String.fromCharCode(dec&0xff);
		dec=dec>>>8;
	}
/*
   for (var i = 0; i<bytes*2; i+=2)
   {
      var t = (dec >>> (i*4)) & 0xFF;
      t = t.toString(16);
      if (t.length != 2) t = "0"+t;
      hex += eval("'\\x"+t+"'");
   }*/

   return hex;
};

?

再对字符数组进行 base64编码,利用charCode取出字符封装的原二进制byte数据

_keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",

encode : function (input) {
		var output = "";
		var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
		var i = 0;

		while (i < input.length) {

			chr1 = input.charCodeAt(i++);
			chr2 = input.charCodeAt(i++);
			chr3 = input.charCodeAt(i++);

			enc1 = chr1 >> 2;
			enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
			enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
			enc4 = chr3 & 63;

			if (isNaN(chr2)) {
				enc3 = enc4 = 64;
			} else if (isNaN(chr3)) {
				enc4 = 64;
			}

			output = output +
			this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
			this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);

		}

		return output;
	},

?


问题:

这里就存在一个问题,js中文中字符内部为2个字符(unicode表示),存储后和具体编码方式相关(utf-8,gbk),而不像英文一样无论(gbk,utf-8)可以视作一个byte,那么我们可以事先将js字符串中的中文字符手动拆解为目标编码 utf-8 表示的三个byte即三个字符,(之所以采用utf-8,而不是其他本地字符编码,encodeURIComponent可以方便得到中文的utf-8编码,而不需要采用外部工具) :

?

utf8Encode:function(input){
		input=encodeURIComponent(input);
		return this._transfer(input);
	},
	
	_transfer:function(input){
		input=input.replace(/%.{2,2}/g,function(m){
			var hex=m.substring(1);
			return String.fromCharCode(parseInt(hex,16));
		});
		return input;
	},

?即将一个字符的utf-8表示的三个byte,封装到三个字符中去,每个字符的charcode表示原来字符utf-8编码的一个byte,这样子的话下面的 base64编码就可以像以前一样了。



演示:

注意目前只有 firefox,safari 稍微正常电

?

演示@google code

?

?

?

?

?

?