JScript快速开发框架 Edk :读写文件 $$.file 包

在 I/O 处理中,最常见的是对文件的操作。JScript既可通过 FSO 读取文件内容,也可以通过 Adodb.Stream 来完成任务。这两种对象都是系统标准的组件。除非主机空间有所禁止,否则一般都可以顺利使用。使用 Adodb.Stream/FSO 读取文件的例子如下。前者仅仅支持 UTF-8 字符集合保存的文件,而后者使用”系统默认编码”。

Adodb.Stream:

/** 
 * 打开文件,读取其内容,返回文本的格式。
 * @static
 * @param	{String}	path		文件路径
 * @param	{Boolean}	isMapPath	是否送入相对路径。True 的话把虚拟路径还原为真实的磁盘路径。
 * @return	{String} 			文本内容
 */
function File_read(path){
	with(new ActiveXObject("Adodb.Stream")){
        type = 2;
        mode = 3;
        charset = "utf-8";
        try {
            open();
            loadFromFile(path);
            return readText();
        }catch (e){
            throw e;
        }finally{
            close();
        }
    }
}
FSO:
// 用使用“系统默认编码”
// { Read: 1, Write: 2, Append: 8 }
with(new ActiveXObject("Scripting.FileSystemObject").openTextFile(filename, 1)){
	fileContent = readAll();
	close();
}
fileContent = new String(fileContent);
fileContent.charset = 'SystemDefault'

比较起流对象 Adodb.Stream,FSO虽然支持 unicode 大字集符,但并不支持 UTF-8 格式。于是,比较搞笑的说法,就是 FSO 只用来生成文件夹,或者 dir 一下目录。

经常听到和碰到字符集的问题,最具代表性的便是“乱码”,——究竟字符集之间存在着什么关系呢?这里简单复习一下基础的知识先。

众所周知,ASNI/ASCII乃字符集之母,及后衍生了许许多多的字符集来为各个国家人民使用。这些字符集之间互不兼容,相同的数字可能表示不同的字符,为信息交流带来了麻烦。于是业界提出了 Unicode 统一字符集的概念,并实践之,已经广泛流行了。Unicode 它将世界上的所有字符映射成一个唯一的数字(所谓的 code point),比如字母 a 对应的数字 0x0041。目前 Unicode 还处于发展中,它所包容的字符越来越多。 而 UTF-8 则为一种编码方式,它可认为是“变长度的 Unicode”,既保留了 unicode 全面的特性,又大大节约了存储空间,为互联网上交换数据带来便利。

但凡方方面面涉及到字符集的,edk.js 均使用 UTF-8 来处理,务求统一为 UTF-8 格式的。

回到本文的代码上。对于已知的 UTF-8 文件,第一种方法里面已经写死,读取 UTF-8 保存的文件内容毫无问题。但是如果需求不是“系统默认编码”,也不是 UTF-8 的文件呢?能否自动判断文件编码(encoding)是哪种字符集的呢?ANSI?Unicode(又分 Small Endian、Big Endian)?还是 UTF-8(又分带 Signature 与否)或其他呢?这里涉及对文件二进制原始数据的检查判断。可是,遗憾的是,JScript天生对二进制”歧视“,不能直接识辨二进制数据(或者说字节数据)。这一点不得不说,连同是脚本的 VBScript 都不如。还记得做验证缩略图时,用 VBS 做方便多了。JS先天的缺陷,令我们 JScript 爱好者十分头疼。不过可是,呵呵,有句话大家说得好,技术无止境,有高人想到用一种方法,就是通过 ADODB.Stream 读写时指定为 437 代码页,然后就可以以文本的形式来读写了。应该说,不失为一种较好的判断文件格式途径。

这里http://www.codeproject.com/KB/scripting/Exsead7.aspx的链接就是刚才提到的高人,Alex,国外技术大牛其文章《Reading and Writing Binary Files Using JScript》的地址。此外,Alex 还有对 Jscript 发送邮件的研究和一个 XML Viewer 工具的制作,十分详细,链接另附如下:

http://www.codeproject.com/KB/scripting/Exsead2.aspx
http://www.codeproject.com/KB/scripting/Exsead5.aspx
http://www.codeproject.com/KB/scripting/Exsead8.aspx

既然还是要用文本来处理,那么就是字符串,操控字符串,——那委实没有多大质的改变,在号称新潮的 Node 开发中也概莫如是。只不过 node 较方便的一点就是提供了 buffter 以处理二进制传输流。原生的话,要为 JS 加入 Byte 字节数据的数据类型、对象、方法、函数估计那一切应该是后话了。此外,虽然通过字符串操控二进制数据会显得比较慢,会不会这样呢?不过这里仅仅只是几个字节的读取,理论上尚可接受的。完整的 read_File_with_Chartset() 函数如下:

/** 
 * 打开文件,读取其内容,返回文本的格式。
 * @param	{String}	path		文件路径
 * @param	{String}	sCharset	指定字符集
 * @return	{String} 				文本内容
 */
function read_File_with_Chartset(filename, sCharset) {
	var stream = new ActiveXObject('adodb.stream');
	var fileContent;

	with(stream){
		type = 2;// 1-二进制,2-文本
		mode = 3;// 1-读,2-写,3-读写
		open();
	
		if (!sCharset) {
			try{
				charset = "437"; // why try, cause some bug now
			}catch(e){}
			loadFromFile(filename);
			
			// get the BOM(byte order mark) or escape(ReadText(2)) is fine?
			switch (escape(readText(2).replace(/\s/g, ''))) {
				case "%3Ca" :
				case "%3Cd" :
				case "%3C%3F" :
				case "%u2229%u2557" :	// 0xEF,0xBB => UTF-8
					sCharset = "UTF-8";
					break;
				case "%A0%u25A0" :		// 0xFF,0xFE => Unicode
				case "%u25A0%A0" :		// 0xFE,0xFF => Unicode big endian
					sCharset = "Unicode";
					break;
				default :
					// 判断不出来就使用GBK,这样可以在大多数情况下正确处理中文
					sCharset = "GBK";	
			}
			close();
			open();
		}
		charset = sCharset;
		loadFromFile(filename);
		fileContent = new String(readText());
		fileContent.charset = sCharset;
		close();
	}
	return fileContent;
}

return fileContent;
edk.js 库通过 Fn.delegate() 方法处理了一下,换句话说,返回预先指定参数的函数。这是因为大多数还是处理 UTF 文件,所以出于便利,委托一新方法执行处理。

至于写入文件内容的方法,如下:

/**
 * 将数据保存到磁盘上。可支持文本数据和二进制数据。
 * @param 	{String} 	data 		要写入的数据,可以是二进制对象。
 * @param 	{String} 	path 		文件路径。
 * @param 	{Boolean} 	isBinary	是否为二进制数据。
 * @param 	{Boolean} 	isMapPath	是否送入相对路径。True 的话把虚拟路径还原为真实的磁盘路径。
 * @return 	{Boolean} 	True		表示操作成功。
 */
,write : function(data, path, isBinary, chartset){
    with(new ActiveXObject("Adodb.Stream")){
        type = isBinary ? 1 : 2;
        if (!chartset && !isBinary)
			charset = "utf-8";
        if (chartset)
			charset = "GB2312";
        try {
			open();
			if(!isBinary){
				writeText(data);
			}else{
				write(data);
			} 
			saveToFile(path, 2);
			return true;
        }catch(e){
			throw e;
        } finally {
			close();
        }
    }
    
    return true;
}
可说的地方不多。不过稍值一提的是 base64 编码输出的函数,通过 XMLDocument  转换(就是不清楚对中文的 base64 转换是否正确):

,base64EncodeText: function (TextStr) {
	var xml_dom = new ActiveXObject("MSXML2.DOMDocument");
	var ado_stream = new ActiveXObject("ADODB.Stream");
	var tmpNode = xml_dom.createElement("tmpNode");
	
	tmpNode.dataType = "bin.base64";
	ado_stream.Charset = "gb2312";
	ado_stream.Type = 2;// 1=adTypeBinary 2=adTypeText
	if (ado_stream.state == 0) {// 0=adStateClosed 1=adStateOpen
		ado_stream.Open();
	}
	ado_stream.WriteText(TextStr);
	ado_stream.Position = 0;
	ado_stream.Type = 1;// 1=adTypeBinary 2=adTypeText
	tmpNode.nodeTypedValue = ado_stream.Read(-1);// -1=adReadAll
	ado_stream.Close();
	return tmpNode.text;
}

最后说说代码中常使用的 with(obj){……}。俺也知道 with 的不好,也不想替 with 语句多辩护,只是贪一时快少写几个单词才用 with 的。呵呵,年纪大了懒得改,这里却请大家将就将就——不过大家要知道,with 还是不好的。

$$.file 位于 /edk/common/ms_com_lib.js 目录中。edk.js 项目主页:http://code.google.com/p/naturaljs/


递归文件夹及下载文件:

$$.file = {
	

//function folderHelper(path, onfile_Fn, onfolder_Fn) {
//	var fso = new ActiveXObject("Scripting.FileSystemObject");
//		
//	if (fso.FolderExists(path)){
//		search(fso.GetFolder(path));
//	}
//	// __Search()
//	function search(folder){
//		for (var e = new Enumerator(folder.SubFolders); !e.atEnd(); e.moveNext()) {
//			var item = e.item();
//			if (typeof onfolder_Fn === "function")
//				onfolder_Fn(item, fso);
//			if (recursive){
//				arguments.callee(item);
//			}
//		}
//		for (var e = new Enumerator(folder.Files); !e.atEnd(); e.moveNext()) {
//			if (typeof onfile_Fn === "function"){
//				onfile_Fn(e.item(), fso);
//			}
//		}
//	}
//}	
	/**
	 * @param {String} folder
	 * @param {Function} fn
	 */
	,getFlatFlies : function(folder, isRecursive, fn, scope){
	    var  
	         fso    = new ActiveXObject("Scripting.FileSystemObject")
	        ,target = fso.getFolder(folder);	
	        
	    if(!fn || typeof(fn) != 'function'){
	    	throw "该函数期待一个合法函数的参数!";
	    }
	    
	    function getFiles(folderObj){
	        var fileObj, i = 0;
	        with(new Enumerator(folderObj.Files)){
	            while (!atEnd()){
	                fileObj = item();
//	                if(fileObj.Name.split('.').pop().indexOf('js') != -1){
//	                    arr.push(fileObj.Path);
//	                }
	                fn.call(scope, fileObj, folderObj, i++);
	                fileObj = null;
	                moveNext();
	            }		
	        } 
	    }
	    // 本目录下的文件
	    getFiles(target);
	    // 子目录下所有的文件
	    if(isRecursive){
		    ;(function(items){
		        var folderObj;
		        with(new Enumerator(items)){
		            while (!atEnd()){
		                folderObj = item();
		                getFiles(folderObj);
		                
		                if(folderObj.subFolders.Count > 0){
		                    arguments.callee(folderObj.subFolders); // 递归
		                }
		                folderObj = null;
		                moveNext();
		            }		
		        }      
		    })(target.SubFolders);  
	    }
	    
	    return true;
	}
	
	/**
	 * 送入一个文件磁盘地址,使用ADODB.Stream组件下载。
	 * 文件大小有限制? Need Huge Server RAM!!
	 * 隐藏下载地址及防盗代码。 防盗链 
	 * @param {String} filePath
	 * @return {Boolean} 是否传送成功。
	 */
	,downFile : function(data){
		var fileObj, fileSize;
			
		with(new ActiveXObject("Scripting.FileSystemObject")){
			fileObj = getFile(filePath);
			if(!fileObj){
				throw '目标文件不存在!';
			}
			fileSize = fileObj.size;
		}
		
	    with(new ActiveXObject("ADODB.Stream")){
	        open();
	        type = 1;
	        loadFromFile(filePath);
		    Response.addHeader("Content-DIsposItIon", "attachment; FIlename=" + F.Name);
		    Response.addHeader("Content-Length", IntFilelength);
	        Response.Buffer      = True
		    Response.CharSet     = "UTF-8";
		    Response.ContentType = "application/x-download";
    		Response.clear();
		    Response.binaryWrite(Read());
		    Response.flush();
		    Close();
	    }
	    return true;
	}
	
};

$$.file.toString = $$.file.read_File_with_Chartset.delegate(null, 'UTF-8');
发布了301 篇原创文章 · 获赞 263 · 访问量 234万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 成长之路 设计师: Amelia_0503

分享到微信朋友圈

×

扫一扫,手机浏览