複製鏈接
請複製以下鏈接發送給好友

文件句柄

鎖定
在文件I/O中,要從一個文件讀取數據,應用程序首先要調用操作系統函數並傳送文件名,並選一個到該文件的路徑來打開文件。該函數取回一個順序號,即文件句柄(file handle),該文件句柄對於打開的文件是唯一的識別依據。要從文件中讀取一塊數據,應用程序需要調用函數ReadFile,並將文件句柄在內存中的地址和要拷貝的字節數傳送給操作系統。當完成任務後,再通過調用系統函數來關閉該文件。
中文名
文件句柄
外文名
file handle
重要性
對於打開的文件是唯一的識別依據
特    點
方便對文件的搜尋與隱藏
領    域
編程語言

文件句柄基本簡介

一個句柄就是一個文件、設備、套接字(socket)或管道的一個名字, 以便幫助記住正在處理的名字,並隱藏某些緩存等的複雜性。(在內部,句柄類似C++語言的“流”stream, 或BASIC中的I/O通道)句柄使得從不同的地方輸入和輸出給不同的地方都較容易。使Perl成為好語言的一個原因是它能和多個文件通訊並一次處理它們。對外部對象友好的符號名字是一個好語言的一個組成部分。
其它使Perl是一個好語言的原因是:Perl是8位的,Perl是可嵌入的,可以通過擴展模式在Perl中嵌入其他程序。Perl是簡明的,網絡上容易使用。環境上是清楚的,容易對話。可以以許多不同的方法引用它(就像前面看到的)。總之,語言本身不是如此嚴格的結構,以至於不能使它超出你的問題。
創建一個句柄,並通過open函數把它和一個文件聯結。open有兩個參數:句柄和你想與它聯結的一個文件名。Perl也給出一些預定義(和預打開的)句柄。stdin是程序的正常輸入通道,而stdout是程序的正常輸出的通道。stderr是一個附加的輸出通道,以便當把輸入轉為輸出時,程序能給出一些説明。
一般地,這些句柄和終端聯結,所以能輸入程序並能看到,但它們也可以和文件聯結。Perl能提供這些預定義句柄,因為操作系統已提供這些。在UNIX下, 進程從它的父進程(一般是一個shell)繼承標準輸入,輸出和錯誤。一個shell的責任之一是建立這些I/O流, 以便子進程不必考慮這些。
既然能為各種目的(輸入、輸出、管道)使用open函數創建句柄,就必須能指明要做什麼。就像在UNIX命令行一樣,你給文件名簡單地加些字符。
open(SESAME, "filename"); #從已存在的文件讀
open(SESAME, "
open(SESAME, ">filename"); #創建一個文件並對它寫
open(SESAME, ">>filename"); #對已有的文件接着寫
open(SESAME, "| output-pipe-command"); #建立一個輸出過濾
open(SESAME, "input-pipe-command |"); #建立一個輸入過濾
可以任意選名字。一旦打開句柄SESAME,它就能被用於存取文件或管道, 直到它被顯式地關閉(用close(SESAME)),或對同一句柄的一系列open把這個句柄和另一文件聯結。
打開一個已打開的句柄是隱式地關閉第一個文件, 使它對文件句柄不可取,並打開一個不同的文件。你必須小心這是你真正想做的。偶然open($handle,$file)的時候,$handle正好包含空串(null)。確認設置$handle為某個單一個量,否則將對空句柄打開一個新的文件。
一旦已為輸入打開一個句柄(或使用stdin),就能使用“行讀操作”<>,讀一行。這個也以鑽石操作(Diamond Operator)聞名,因為它的形狀<>像鑽石。這個鑽石操作包含你想讀的句柄()。使用stdid句柄讀用户提供的答案,如下:
空鑽石操作<>,將從命令行指定的所有文件讀;如果沒有指定,從stdin讀。(這是許多UNIX“過濾”程序的標準行為)
print STDOUT "Enter a number: "; #請求輸入一個數
$number = ; #輸入一個數
print STDOUT "The number is $number"; #輸出這個數
print語句中stdout做什麼?這就是使用一個輸出句柄的方法之一。一個句柄可以作為print語句的第一個參數,如果存在,告訴往哪兒輸出。在例子中,句柄是冗餘的,因為輸出已經是stdout。對於輸入的缺省是stdin,對於輸出的缺省是stdout。
如果試上面的例子,可以得到一個特別的空行。因為讀時沒有自動地從輸入行中刪除換行符(newline)(例如,輸入"9")。對於這些情況,Perl提供chop和chomp函數以刪除換行符。chop將不加區別地刪除(並返回)傳給它的最後一個字符,而chomp只刪除記錄標識的末尾(一般地是""),並返回這樣刪除的字符數。經常有這樣輸入一行:
chop($number = ); #輸入一個數並刪除換行符
意思是:
$number = ; #輸入一個數
chop($number); #刪除換行符
mov
int
mov
int
endp
ends
end ah,9
21h
ah,4ch
21h
main
; 結束進程
這是一個不尋常的程序,它的特殊性就在於使用了“不尋常”的文件句柄。打開的第一個文件的句柄號是05H而不是00H,之所以這樣是因為句柄號00H-04H已經被佔用了。而且更為特殊的是這五個句柄不是賦予5個文件的,而是賦予5種硬件設備。文件和硬件設備竟然又出現了某種聯繫,要弄清楚這個問題,還是要從一些實際現象出發。
C語言中的fprintf函數有個用法:
fprintf(STDERR,"DANGER!!!......Found a VIRUS......");
在這個位置上放了一個稱為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提供了那5個特殊句柄的原因。
下面的表列出了這5個句柄所代表的硬件設備,其中0、1、2三個句柄是最常用的。這5種設備在DOS啓動之後就已經“打開”,因此可以直接使用這5個句柄而不必再編制代碼將其打開。有關這5個特殊句柄還有一些更值得深思的地方,比如,能否使用3FH功能從句柄2所表示的設備中讀入信息,能否使用40H功能向句柄3所表示的設備輸出信息,能否用3EH功能關閉某個句柄所表示的設備。
句柄
設備名稱
邏輯設備名
缺省設備
00
標準輸入設備
鍵盤
01
標準輸出設備
CON
顯示器
02
標準錯誤設備
CON
顯示器
03
標準輔助設備
AUX
04
標準列表設備
PRN
打印機
至此有關文件操作的幾個重要功能——建立、打開、讀寫、關閉,都已經被討論。

文件句柄輔助功能

句柄是操作系統在生成對象時分配給對象的唯一標識。 通過句柄可以獲取操作系統提供的服務。句柄不同於指針,如果得到了一個對象的指針,就可以在此對象上做任何事了。於是系統不給指針,而給用户一個加了限制的,用於跟蹤對象的指針的標識——句柄。系統使用句柄向外提供服務就相對安全了。操作系統是通過API提供服務的,對於用户來説,句柄等同於對象指針,但實際上句柄和指針根本不是一回事。