系统和很多软件都有用到 .ini 配置文件。它的结构比较简单,包括注释、节和参数,很容易处理。
注释都是以分号开头的,节是开头结尾是一对中括号的,参数是用等号分隔的,比如下面这个
;EXESCOPE配置内容
;注册信息
[Reg]
;用户名
Name=SpringBrother
ID=A185704471
[Window]
Left=174
Top=86
Width=594
Height=425
[DlgWin]
Left=124
Top=127
;历史记录
[Recent]
我把整个INI文件的内容称为一个 IniObject 对象,第一行是它的注释;
到第四行出现了第一个节,称为一个 Section 对象,名称为 Reg上面的第三行是它的注释;
到第六行出现了第一个参数,称为一个 Parameter 对象,他的名称为 Name,值为SpringBrother,上面的第五行是它的注释;
一直到第九行才出现第二个节,在第四行到第九行之间的所有参数都是属于 Reg 这节的。
给 IniObject、 Section、 Parameter 这三种对象定义属性和方法,使得可以读取文件内容进行转换,或者重头创建,然后可以保存,这样就可以从对象的角度,读取或者写INI文件了。
【Parameter 对象】
参数。
构造函数
Parameter(name[, value[, comments]])
属性
name String。R/W。参数名。
value String。R/W。参数值。
comments String。R/W。注释。
方法
toString() String。格式化的字符串。
【Section 对象】
节。
构造函数
Section(name[, comments])
属性
name String。R/W。参数名。
comments String。R/W。注释。
parameters Array<Parameter>。R/W。包含所有的 Parameter 对象的数组。
方法
getParameterNames() Array<String>。包含 parameters 中全部 name。
add(obj) this。添加一个 Parameter 对象。
add(name[, value[, comments]]) this。初始化并添加一个 Parameter 对象。
get(name) Parameter。根据 name 获取一个 Parameter 对象。
remove(name) Parameter。根据 name 删除一个 Parameter 对象。
sort(isAscOrDesc) this。根据 name 将所有参数正序或倒序排列。
toString() String。格式化的字符串。
【IniObject 对象】
整个INI文件。
构造函数
IniObject([iniFileName])
属性
comments String。R/W。注释。
sections Array<Section>。R/W。包含所有的 Section 对象的数组。
方法
getSectionNames() Array<String>。包含 sections 中全部 name。
read(secName, paramName) String。读取一个参数值。
add(obj) this。添加一个 Section 对象。
add(name[, comments]) this。初始化并添加一个 Section 对象。
get(name) Section。根据 name 获取一个 Section 对象。
remove(name) Section。根据 name 删除一个 Section 对象。
sort(isAscOrDesc) this。根据 name 将所有节正序或倒序排列。
sortAll(isAscOrDesc) this。根据 name 将所有节及其参数正序或倒序排列。
toString() String。格式化的字符串。
saveAs(fileName) void。另存为文件。
save() void。保存。
finalize() void。取消对 Array 对象的更改。
以下是源代码
- var IniObject = function(iniFileName) {
-
- this.__version = "1.4";
-
- //注释。结尾无换行符
- this.comments;
-
- //所有的节。数组元素为 Section 对象。
- this.sections = [];
-
- //原始文件名。不可更改
- var fileName;
-
- //各种类型的文本格式
- var regExp = {
- Cr : new RegExp().compile("\\r", "g"),
- CrLf : new RegExp().compile("(\\r\\n)|[\\r\\n]", "g"),
- Blank : new RegExp().compile("^\\s*$"),
- NonBlank : new RegExp().compile("\\S"),
- Useless : new RegExp().compile("^;\\s*$", "gm"),
- Trim : new RegExp().compile("(^\\s+)|(\\s+$)", "gm"),
- Comment : new RegExp().compile("^\\s*;(.*)$"),
- Section : new RegExp().compile("^\\s*\\[([^]]+)]\\s*$"), //Original
- Parameter : new RegExp().compile("^(\\s*[^=]+)=(.*)$"), //Original
- TSection : new RegExp().compile("^\\s*\\[\\s*([^]]*[^\\s])\\s*]\\s*$"), //Trimed Section name
- TParameter : new RegExp().compile("^\\s*([^=]*[^\\s])\\s*=(.*)$") //Trimed Parameter name
- };
-
- //用于较宽泛的比较
- var easylize = function(str) {
- if(str) {
- return str.replace(regExp.Trim, "").toLowerCase();
- } else {
- return str;
- }
- };
-
- //将纯文本转换为INI文件中的注释行
- var parseCommentLines = function(comments) {
- var s = "";
- if(comments && comments.length > 0) {
- //行首增加一个分号“;”
- s = ";" + comments.replace(regExp.CrLf, "\r;");
- //空行
- s = s.replace(regExp.Useless, "");
- //末尾换行(不能去掉这个处理,不然后面无法形成没有注释的行)
- s = s.replace(regExp.Cr, "\r\n") + "\r\n";
- }
- return s;
- };
-
-
- //查找一个指定name的对象在数组中的序号。找不到则返回 -1
- Array.prototype.indexOf = function(paramName) {
- var index = -1;
- for(var i = 0; i < this.length; i++) {
- if(easylize(this[i].name) == easylize(paramName)) {
- index = i;
- break;
- }
- }
- return index;
- };
- //添加一个指定类型的对象到数组中
- Array.prototype.addObject = function(objType, x, y, z) {
- var obj;
- if(typeof x === "object" && x.name) {
- obj = x;
- } else {
- //obj = new objType(x.replace(regExp.Trim, ""), y, z); //Trimed Object name
- obj = new objType(x, y, z);
- }
- var index = this.indexOf(obj.name);
- if(index >= 0) {
- //覆盖
- this.splice(index, 1, obj);
- } else {
- //新建
- index = this.length;
- this.push(obj);
- }
- //return this[index];
- return this;
- };
- //获取一个指定name的对象
- Array.prototype.getObject = function(x) {
- var index = this.indexOf(x);
- return index >= 0 ? this[index] : undefined;
- };
- //删除一个指定name的对象
- Array.prototype.removeObject = function(x) {
- var index = this.indexOf(x);
- return index >= 0 ? this.splice(index, 1)[0] : undefined;
- };
- //将数组中所有对象按照name排序
- Array.prototype.sortObject = function(b) {
- var x = (b === undefined) ? 1 : (b ? 1 : -1);
- this.sort(function(a, b) {
- return easylize(a.name) > easylize(b.name) ? x : -x;
- });
- };
-
-
- //返回包含所有节 name 的数组
- this.getSectionNames = function() {
- var arr = [];
- for(var i = 0; i < this.sections.length; i++) {
- arr.push(this.sections[i].name);
- }
- return arr;
- };
-
- //读取一个参数值
- this.read = function(secName, paramName) {
- var s = this.sections.getObject(secName);
- if(s) {
- var p = s.get(paramName);
- if(p) {
- return p.value;
- }
- }
- return undefined;
- };
-
- //添加一个节。如果已经存在则会覆盖同名的节
- this.add = function(s, c) {
- this.sections.addObject(Section, s, c);
- return this;
- };
-
- //获取一个 Section 对象。不存在则返回 undefined
- this.get = function(secName) {
- return this.sections.getObject(secName);
- };
-
- //删除一个节并返回删除的 Section 对象
- this.remove = function(secName) {
- return this.sections.removeObject(secName);
- };
-
- //将所有的节按 name 排序
- this.sort = function(isAscOrDesc) {
- this.sections.sortObject(isAscOrDesc);
- return this;
- };
-
- //将所有的节以及其中的参数按 name 排序
- this.sortAll = function(isAscOrDesc) {
- this.sort(isAscOrDesc);
- for(var i = 0; i < this.sections.length; i++) {
- this.sections[i].sort(isAscOrDesc);
- }
- return this;
- };
-
- //转换为 INI 文件格式的文本
- this.toString = function() {
- var s = parseCommentLines(this.comments);
- //隔开。防止排序后误认为是 Section 的注释
- if(this.comments && this.sections.length > 0) {
- s += "\r\n";
- }
- for(var i = 0; i < this.sections.length; i++) {
- s = s + this.sections[i].toString();
- }
- return s;
- };
-
- //另存为文件
- this.saveAs = function(fn) {
- var fso = new ActiveXObject("Scripting.FileSystemObject");
- var f = fso.OpenTextFile(fn, 2, true);
- f.Write(this.toString());
- f.Close();
- };
-
- //保存文件
- this.save = function() {
- if(fileName) {
- this.saveAs(fileName);
- } else {
- throw "File name not specified.";
- }
- };
-
- //取消对Array的更改
- this.finalize = function() {
- delete Array.prototype.indexOf;
- delete Array.prototype.addObject;
- delete Array.prototype.getObject;
- delete Array.prototype.removeObject;
- delete Array.prototype.sortObject;
- };
-
-
- /***************************
- ;comment
- name=value
- ***************************/
- var Parameter = function (n, v, c) {
- if(n === undefined || n === null || regExp.Blank.test(n)) {
- throw "The name of parameter must be specified and shouldn't be null.";
- return undefined;
- } else {
- return {
- name : n,
- value : v === false ? "false" : v || "",
- comments : c || "",
- toString : function() {
- return (parseCommentLines(this.comments)) + this.name + "=" + this.value;
- }
- };
- }
- };
-
- /***************************
- ;comment
- [section]
- ***************************/
- var Section = function (n, c) {
- if(n === undefined || n === null || regExp.Blank.test(n)) {
- throw "The section name must be specified and shouldn't be null.";
- return undefined;
- } else return {
- name : n,
- //为了方便,没有填注释的默认开头换行隔开;如果不要空行,可设置为空字符串 ""
- comments : c === undefined ? " " : c,
- parameters : [],
- getParameterNames : function() {
- var arr = [];
- for(var i = 0; i < this.parameters.length; i++) {
- arr.push(this.parameters[i].name);
- }
- return arr;
- },
- add : function(p, v, c) {
- this.parameters.addObject(Parameter, p, v, c);
- return this;
- },
- get : function(paramName) {
- return this.parameters.getObject(paramName);
- },
- remove : function(paramName) {
- return this.parameters.removeObject(paramName);
- },
- sort : function(isAscOrDesc) {
- this.parameters.sortObject(isAscOrDesc);
- return this;
- },
- toString : function() {
- var s = parseCommentLines(this.comments);
- s += "[" + this.name + "]";
- for(var i = 0; i < this.parameters.length; i++) {
- s = s + "\r\n" + this.parameters[i].toString();
- }
- //每节最后都有换行
- return s + "\r\n";
- }
- }
- };
-
-
- /*****************************************
- 加载文件内容
- *****************************************/
- if(iniFileName && iniFileName.length > 0) {
- var fso = new ActiveXObject("Scripting.FileSystemObject");
- if(!fso.FileExists(iniFileName)) {
- throw "File not found:\r\n" + iniFileName;
- return;
- } else {
- var f = fso.OpenTextFile(iniFileName, 1);
- var currComments, currSection;
- while(!f.AtEndOfStream) {
- var strLine = f.ReadLine();
- if(regExp.Blank.test(strLine)) {
- if(currComments) {
- //文件注释:从文件开头以来第一段连续的注释
- if(this.comments === undefined && regExp.NonBlank.test(currComments)) {
- this.comments = currComments;
- currComments = null;
- } else {
- currComments += " \r\n";
- }
- } else {
- currComments = " ";
- }
- } else if(regExp.Comment.test(strLine)) {
- var commentLine = strLine.replace(regExp.Comment, "$1");
- if(currComments) {
- currComments += "\r\n" + commentLine;
- } else {
- currComments = commentLine;
- }
- } else if(regExp.Section.test(strLine)) {
- //没有文件注释
- if(this.comments === undefined) {
- this.comments = "";
- }
- var currSecName = strLine.replace(regExp.Section, "$1");
- this.add(currSecName, currComments);
- currSection = this.get(currSecName);
- currComments = null;
- } else if(regExp.Parameter.test(strLine)) {
- if(!currSection) {
- throw "File format error. Section name must be the first, not a parameter.";
- break;
- }
- var currParamName = strLine.replace(regExp.Parameter, "$1");
- var currParamValue = strLine.replace(regExp.Parameter, "$2");
- currSection.add(currParamName, currParamValue, currComments);
- currComments = null;
- } else {
- throw "File format error. Couldn't parse :\r\n" + strLine;
- break;
- }
- }
- f.Close();
- fileName = iniFileName;
- }
- } else {
- //不从文件读,则赋值,以免toString出错
- this.comments = "";
- }
-
- //It's better to be initalized by "new IniObject(fn)"
- //return this;
- };
复制代码
|