使用TCL脚本读取配置文件

发表于:2007-4-04 13:40

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:叶晖 兰海    来源:51testing

摘 要unix下使用TCL脚本读取配置文件;错误处理.

关键词TCL、配置文件、unix

 

一.应用范围

在实际工作中,TCL脚本对于一些简单的工作裨益甚大。通常编写脚本都有一定的模式,首先从配置文件读入配置项,初始化变量,然后进行处理,最后输出,在程序的运行过程中需要把一些信息写入日志文件,而调试信息写入日志文件和直接输出到屏幕都可以。

使用任何一种脚本,通常也都会根据实际情况建立起自己的函数库,而这个函数库中对配置文件配置项的读取无疑是非常基本而重要的。

这篇文章的本意是引导刚接触TCL脚本的朋友尽快上手,所以有些细节的说明文字比较细。

 

二.程序讲解

构建一个配置文件,尽可能的接近实际应用:

文件名:config.ini

文件内容:

       #

#这是注释行

#

 

[]

key1=value1        #注释

 

[section1]

key2=value2

 

[section2]

key1=value2

 

[section1]

key1=xxxxxx       #这是最后的返回

 

[section1]

key1=value2

 

 

现在开始对程序的说明:

 

;#-------------------------------------------------------------------------

;#功能:从配置文件中读取配置项

;#输入:1. configFile:配置文件名称

;#      2. Section :段名称

;#      3. Key :关键字

;#      4. Comment :注释符,缺省为井号

;#      5. Equal :关键字和值的分隔符,缺省为等号

;#输出:1. Value :相应的值

;#-------------------------------------------------------------------------

 

1.过程的定义:

  格式:proc name args body

  要点:

Ø        参数列表使用花括号引起;

Ø        变量没有类型;

Ø        变量之间使用空格间隔;

Ø        如果参数有缺省值,使用花括号引起,并赋值

proc getConfig { configFile Section Key {Comment "#"} {Equal "="}} {

      set Value ""                  ;#记录过程返回的值  

      set FindSection 0             ;#记录是否找到了section

 

2.错误的处理

      格式:catch script ?varName?

      功能:执行script,如果成功返回TCL_OK(0),否则返回TCL_ERROR(1),提示结果存在varName中。比如下面如果打开文件成功,errMsg返回的就是类似file3这样的字符串,此时err返回的是TCL_OK,就是零;如果文件不存在,errMsg返回的类似:couldn't open "config1.ini": no such file or directory,此时err返回TCL_ERROR,就是一。

 

3.文件的读写

      格式:openfile fileName ? access ? permission

      讲解:

Ø        fileName是文件名称;

Ø        access是存取模式,可以为r, r+, w, w+, a, a+六种模式,rr+a三种模式文件必须已经存在,其他三种模式文件不存在就创建一个。本文用的r模式,所以文件不存在会提示错误,而不是自动建立一个;

Ø        permission是权限,举例说明:
有权限为:000 000 000:第一组三位为user权限;第二组三位为同组其他用户的权限;第三组三位为其他组所有人的权限。每个三位的权限依次代表读,写,执行。如果有相应的权限就设置为一,没有设置为0。然后三位为组转成十进制数。

Ø        文件打开后就可以使用其文件id,使用完后记得关闭文件

 

      ;#打开配置文件

      set err [catch {set fileid [open $configFile r]} errMsg]

      if {$err == 1} {

             puts "errMsg : $errMsg"

             return $Value

      }

 

      ;#成功打开文件后,一行一行的加以分析

      set rowid 0                      ;#记录当前行数,程序调试时打印调试信息使用的

      seek $fileid 0 start                       ;#定位到文件头

      while {[eof $fileid] != 1} {                ;#读取文件内容

 

4.变量的自动增长使用命令incr,也可以使用set rowid [expr $rowid + 1],显然前者更简捷

             incr rowid                         ;#记录行数,从一开始

      

             ;#读出一行

             gets $fileid line

             

5.先期处理行,因为注释有两种情况,行中的注释和整行注释,先去掉注释,然后去左右空格就可以得到真正需要的内容;如果先去空格,再去注释,由于行中的注释和内容之间有空格,这样最后得到的内容在去掉行中注释后,会在后面留下一些空格。所以需要先去掉注释,后去掉空格。

 

6.得到一个字符串在另一个字符串中首先出现的位置,使用函数string first

      格式:string first string1 string2

      讲解:返回string1string2中第一次出现的位置;如果string1不在string2中,返回-1

 

7.下面有一个细节是初学者经常犯错的地方,那就是:} else {,这里必须严格的花括号,空格,else,空格,花括号,不能把花括号写到上一行或者下一行。

 

8.返回一个字符串的子串使用string range函数

      格式:string range string1 frompos topos

      讲解:取string1的从frompostopos之间的字符串,注意这里字符串下标是从零开始的,所以用string length string1得到的字符串的长度比字符串最后一个字符的位置值要大一。如果取一个字符串中的某个字符就可以使用函数string index string1 pos

 

9exprunix shell中一样,是进行数学运算的函数。

 

             ;#先去掉注释,再去掉两端的空格

             set commentpos [string first $Comment $line]       ;#得到注释符号的位置

             if { $commentpos == 0 } {

                    ;#行以注释符号开头,忽略掉该行

             } else {

                    if { $commentpos != -1 } {       ;#行中有注释符号,去掉注释

                           set line [string range $line 0 [expr $commentpos-1]]

                    }

                    

                    set line [string trim $line]         ;#去掉两端的空格

                    ;# puts "$rowid : line : $line"

                    

10.在tcl脚本中,循环中有break命令跳出循环,continue跳到循环的开头。不过因为括号的使用,其实这里写不写continue都没有问题。

 

                    ;#如果是空就继续循环

                    if { $line == "" } {

                           ;#回循环

                           continue

                    } else {

                           ;#先找section

                           set linelen [string length $line]        ;#字符串长度

                           set lastpos [expr $linelen - 1 ]         ;#字符串最后的位置

                           ;# puts "$rowid :len: $linelen  lastpos: $lastpos"

                           if { [string index $line 0] == "\[" && [string index $line $lastpos] == "\]" } {

                                  ;#如果是查找的section,修改标志位;如果不是相应的section,需要将标志重新赋值

                                  if { [string range $line 1 [expr $lastpos - 1 ]] == $Section } {  

                                         ;# puts "$rowid: find section : $Section"

                                         set FindSection 1

                                  } else {

                                         set FindSection 0

                                  }

                           } else {

                                  ;#已经找到了section才继续找key

                                  if { $FindSection == 1 } {

                                         set equalpos [string first $Equal $line]  ;#得到等号的位置

                                         if { $equalpos != -1} {

                                                ;#如果就是找寻的key,结束循环

                                                if { [string range $line 0 [expr $equalpos - 1]] == $Key } {

                                                       puts "$rowid: find key"

                                                       set Value [string range $line [expr $equalpos + 1] [string length $line]]

                                                       puts "$rowid: find value: $Value"

                                                       break

                                                }

                                         } else {

                                                ;#回循环

                                         }

                                  } else {

                                        ;#回循环

                                  }

                           }

                    }

             }

      }

 

      ;#关闭文件

      close $fileid

      

      return $Value

}

 

 

set val ""

 

;#测试正常情况下

set val [getConfig "config.ini" "section1" "key1"]

puts "val : $val"

 

;#测试文件不存在的情况下

set val [getConfig "config1.ini" "section1" "key1"]

puts "val : $val"

 

 

该程序在unix环境下调试通过。

 

三.伪代码

为了便于理解程序,特写了下面的伪代码:

 

打开配置文件

      IF出错THEN

        过程结束

      END IF

 

文件打开成功,定位到文件头

WHILE没有到文件尾

      读出一行

 

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017