特點
一個句柄就是你給一個檔案,設備,套接字(socket)或管道的一個名字, 以便幫助你記住你正處理的名字, 並隱藏某些快取等的複雜性。(在內部, 句柄類似C++語言的流(streams), 或BASIC中的I/O通道)句柄使你從不同的地方輸入和輸出給不同的地方都較容易。使Perl成為好語言的一個原因是它能和多個檔案通訊並一次處理他們。對外部對象友好的符號名字是一個好語言的一個組成部分[1]。
[1]其他使Perl是一個好語言的是: 它是8位的, 是可嵌入的, 你能通過擴展模式在Perl中嵌入其他程式。它是簡明的,網路上容易使用。環境上是清楚的,容易對話。你能以許多不同的方法引用它(就象前面看到的)。總之,語言本身不是如此嚴格的結構,以至於你不能使它超出你的問題。又回到TMTOWTDI。
你創建一個句柄,並通過open函式把它和一個檔案聯結。open有兩個參數: 句柄和你想與它聯結的一個檔案名稱。Perl也給出一些預定義(和預打開的)句柄。STDIN是你程式的正常輸入通道, 而STDOUT是你程式的正常輸出的通道。STDERR是一個附加的輸出通道, 以便當把輸入轉為輸出時, 程式能給出一些說明。
[2]一般地, 這些句柄和你的終端聯結, 所以你能輸入你的程式並能看到, 但他們也可以和檔案聯結。Perl能給你這些預定義句柄, 因為你的作業系統已提供這些。在UNIX下, 進程從他的父進程(一般是一個shell)繼承標準輸入, 輸出和錯誤。一個shell的責任之一是建立這些I/O流, 以便子進程不必考慮這些)。
既然你能為各種目的(輸入, 輸出, 管道)使用open函式創建句柄, 你就必須能指明你要做什麼。就象在UNIX命令行一樣, 你給檔案名稱簡單地加些字元。
open(SESAME, "filename"); #從已存在的檔案讀
open(SESAME, "<filename");#顯式地,同上面
open(SESAME, ">filename"); #創建一個檔案並對它寫
open(SESAME, ">>filename"); #對已有的檔案接著寫
open(SESAME, "| output-pipe-command"); #建立一個輸出過濾
open(SESAME, "input-pipe-command |"); #建立一個輸入過濾
就象你看到的, 你可以任意選名字。一旦打開句柄SESAME, 它就能被用於存取檔案或管道, 直到它被顯式地關閉(用close(SESAME)), 或對同一句柄的一系列open把這個句柄和另一檔案聯結[3]。
[3]打開一個已打開的句柄是隱式地關閉第一個檔案, 使它對檔案句柄不可取,並打開一個不同的檔案。你必須小心這是你真正想做的。有時,偶然碰巧,比如,當你open($handle,$file)時, $handle正好包含空串(null)。確認設定$handle為某個單一個量, 否則你將對空句柄打開一個新的檔案。
一旦你已為輸入打開一個句柄(或你使用STDIN), 你就能使用"行讀操作"<>, 讀一行。這個也以鑽石操作聞名,因為它的形狀。這個鑽石操作包含你想讀的句柄(<SESAME>)[4]。使用STDID句柄讀用戶提供的答案, 如下:
[4]空鑽石操作<>, 將從命令行指定的所有檔案讀, 如果沒有指定, 從STDIN讀。(這是許多UNIX"過濾"程式的標準行為)
print STDOUT "Enter a number: "; #請求輸入一個數
$number = <STDIN>; #輸入一個數
print STDOUT "The number is $number"; #輸出這個數
你明白我們給你的例子嗎?在print語句中STDOUT做什麼?這就是你使用一個輸出句柄的方法之一。一個句柄可以作為print語句的第一個參數, 如果存在, 告訴往哪兒輸出。在例子中,句柄是冗餘的,因為輸出已經是STDOUT。對於輸入的預設是STDIN, 對於輸出的預設是STDOUT。(在班級例子的18行, 我們為避免使你混淆, 我們省略了。)
我們也有一件事使你不明白。如果你試上面的例子,你可以注意到你得到一個特別的空行。因為讀時沒有自動地從你的輸入行中刪除換行符(newline)(例如, 你輸入"9")。對於這些情況,當你想刪除換行符時,Perl提供chop和chomp函式。chop將不加區別地刪除(並返回)傳給它的最後一個字元, 而chomp只刪除記錄標識的末尾(一般地是""), 並返回這樣刪除的字元數。你將經常看到這樣輸入一行:
chop($number = <STDIN>); #輸入一個數並刪除換行符
意思是:
$number = <STDIN>; #輸入一個數
chop($number); #刪除換行符
mov
int
mov
int
endp
ends
end ah,9
21h
ah,4ch
21h
main
;結束進程
這是一個不尋常的程式,它的特殊性就在於使用了"不尋常"的檔案句柄。還記得前面我們討論檔案句柄時所遺留的那個問題嗎?我們打開的第一個檔案的句柄號是05H而不是00H,之所以這樣是因為句柄號00H-04H已經被占用了。而且更為特殊的是這五個句柄不是賦予五個檔案的,而是賦予五種硬體設備。這聽上去好象越來越亂了,檔案和硬體設備竟然又出現了某種聯繫,實在讓人搞不明白。我想若要弄清楚這個問題,我們還是要從一些實際現象出發。
學過C語言的朋友一定接觸過fprintf函式的這樣一個用法:
fprintf(STDERR,"DANGER!!!......Found a VIRUS......");
本來,在STDERR這個位置上應該是指向一個檔案的指針,這個指針的含義和我們現在討論的檔案句柄是一樣的(我想也許彙編語言中的檔案句柄就是C語言中檔案指針的實質,我沒有查過權威資料,這個看法是否正確還有待檢驗)。現在我們在這個位置上放了一個稱為STDERR的常量,而且我們知道這樣使用fprintf函式可以使引號中的文字出現在顯示器上而不是某個檔案中,而顯示器又恰好是一個硬體設備。由此看來,檔案、檔案指針和硬體設備確實應該存在某種聯繫,這種聯繫並非在彙編語言程式設計中有體現,在C這樣的高級語言中已經體現出來了。那么STDERR又是個什麼東西呢?
這個常量出現在名為STDIO.H的一個包含檔案中,在C語言中它被稱為"標準錯誤輸出設備(STanDard ERRor output device)"C語言中還有兩個比較常用的常量,分別為STDIN和STDOUT,即標準輸入和標準輸出設備。這三種設備通常都與鍵盤和顯示器有關,使用fprintf函式從STDIN讀入數據時相當於等待鍵盤輸入;而向STDOUT或STDERR輸出的內容都會出現在顯示器上。這就有點兒象我們剛剛給出的那個彙編程式,在那個彙編程式中我們在輸出數據時使用了一個特殊的句柄,結果導致了所有的文字都出現於顯示器上而沒有寫入什麼檔案中。
看來我們所使用的那個特殊句柄代表的是顯示器而不是檔案。我們所使用的DOS系統還有這樣一個有趣的功能不知道你是否使用過,那就是"重定向"功能。如果在DOS狀態下按下面這樣的格式使用DIR命令,大家就會發現檔案和設備確實具有某種不尋常的聯繫:
C:\DOS\>DIR>FILE.LST
本來會出現在顯示器上的一行行檔案名稱都跑到一個名叫"FILE.LST"的檔案中去了。由此我們構想這樣一個結論:我們通過調用DOS的檔案句柄功能不僅可以操作檔案,同樣可以操作一些硬體設備。
這個結論是完全正確的,事實上檔案與設備本身就具有一些相似的特點:檔案可以讀入或寫出,而硬體設備同樣可以"讀入"(鍵盤)和"寫出"(顯示器、印表機)。既然它們具有這樣相同的特性,當然可以使用同樣的形式來操作,這就是DOS為我們提供了那五個特殊句柄的原因。我們下面就來詳細談談這五個特殊的句柄:
表8-3列出了這五個句柄所代表的硬體設備,其中0、1、2三個句柄是我們最常用的。這五種設備在DOS啟動之後就已經"打開",所以我們可以直接使用這五個句柄而不必再編制代碼將其打開。有關這五個特殊句柄還有一些更值得深思的地方,比如,我們能否使用3FH功能從句柄2所表示的設備中讀入信息?能否使用40H功能向句柄3所表示的設備輸出信息?我們能否用3EH功能關閉某個句柄所表示的設備?分析這樣的問題也非難事,編個程式試一試即可。
句 柄 設備名稱 邏輯設備名 預設設備
00 標準輸入設備 CON 鍵盤
01 標準輸出設備 CON 顯示器
02 標準錯誤設備 CON 顯示器
03 標準輔助設備 AUX 串列口
04 標準列表設備 PRN 印表機
至此有關檔案操作的幾個重要功能--建立、打開、讀寫、關閉--我們都已經討論,不是很全面,沒有深入的地方還要大家自行研究。我們下面的任務就是來討論檔案句柄的一些輔助功能,以此做為這一內容的結束。
句柄是作業系統在生成對象時分配給對象的唯一標識。 通過句柄可以獲取作業系統提供的服務。句柄不同於指針,如果你得到一個對象的指針,那你就可以在此對象上為所欲為了!於是系統不給你指針,而給用戶一個加了限制的,用於跟蹤對象的指針的標識——句柄!系統使用句柄向外提供服務就相對安全了! 作業系統是通過API提供服務的,對於用戶來說,句柄等同於對象指針,但實際上句柄和指針根本不是一回事!