天天看點

使用TCL腳本讀取配置檔案

引用位址:http://www.rjzl.gov.cn/news.asp?id=814

摘 要: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+ 六種模式,r 、r+

和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        講解:傳回string1在string2中第一次出現的位置;如果string1不在string2中,

傳回-1 7.下面有一個細節是初學者經常犯錯的地方,那就是:} else { ,這裡必須嚴格

的 花括号,空格,else,空格,花括号,不能把花括号寫到上一行或者下一行。 8.傳回一個字元串的子串使用string range函數        格式:string range string1 frompos topos        講解:取string1的從frompos到topos之間的字元串,注意這裡字元串下标

是從零開始的,是以用string length string1得到的字元串的長度比字元串最後一

個字元的位置值要大一。如果取一個字元串中的某個字元就可以使用函數string index

string1 pos。 9.expr 和unix 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 沒有到檔案尾        讀出一行

       處理得到的行,先去掉行中的注釋,再去掉行左右的空格               IF 行為空 THEN        ELSE               行不為空               IF [開頭 ]結束 THEN                      得到SECTION                      IF 得到的SECTION就是要找的SECTION THEN                             置标志位                      ELSE                             清空标志位                      END IF               ELSE                      IF 已經找到SECTION了 THEN                             IF 行中有等号 THEN                                    IF 等号左邊的是在查找的KEY THEN                                           取得等号右邊的值,跳出循環                                    ELSE                                           等号左邊不是在查找的KEY,繼續下

一行                                    END IF                             ELSE                                    行中沒有等号,繼續下一行                             END IF                      ELSE                             還沒有找到SECTION,繼續下一行                      END IF               END IF        END IF

關閉檔案 傳回值                       四.讨論 這個程式本身比較簡單,主要目的是想通過這個程式讓tcl初學者對tcl有個感性認

識。真正在工作使用中,這個腳本需要改進的地方還有很多。 比如配置檔案比較小的話,可以讀一個配置項打開一次檔案。當配置檔案大了以後,

這種方法顯然效率比較低,可能需要一次将檔案的内容全部讀入一個清單中,然後

進行讀取,這樣速度會有提高。再比如錯誤處理隻是在過程中将錯誤資訊顯示到屏

幕上,是不是應該定義一個錯誤資訊的全局變量來傳出過程,或者使用upvar 直接

修改錯誤資訊變量。否則傳回的值是空,并不能确定是配置的值的确是空還是執行

中出現了錯誤。

繼續閱讀