可以看到,這兩行并未按我們想象的順序存貯,為什么呢?我們來分析一下這段程序。 第3行重定向標準輸出文件,方法是打開文件file1將它與文件變量STDOUT關聯,這也關閉了標準輸出文件。第4行重定向標準錯誤文件,參數>&STDOUT告訴Perl解釋器使用已打開并與STDOUT關聯的文件,即文件變量STDERR指向與STDOUT相同的文件。第5、6行分別向STDOUT和STDERR寫入數據,因為這兩個文件變量指向同一個文件,故兩行字符串均寫到文件file1中,但順序卻是錯誤的,怎么回事呢? 問題在于UNIX對輸出的處理上。當使用print(或其它函數)寫入STDOUT等文件時,UNIX操作系統真正所做的是把數據拷貝到一片特殊的內存即緩沖區中,接下來的輸出操作繼續寫入緩沖區直到寫滿,當緩沖區滿了,就把全部數據實際輸出。象這樣先寫入緩沖區再把整個緩沖區的內容輸出比每次都實際輸出所花費的時間要少得多,因為一般來說,I/O比內存操作慢得多。 程序結束時,任何非空的緩沖區都被輸出,然而,系統為STDOUT和STDERR分別維護一片緩沖區,并且先輸出STDERR的內容,因此存貯在STDERR的緩沖區中的內容line 2出現在存貯在STDOUT的緩沖區中的內容line 1之前。 為了解決這個問題,可以告訴Perl解釋器不對文件使用緩沖,方法為: 1、用select函數選擇文件 2、把值1賦給系統變量$| 系統變量$|指定文件是否進行緩沖而不管其是否應該使用緩沖。如果$|為非零值則不使用緩沖。$|與系統變量$~和$^協同工作,當未調用select函數時,$|影響當前缺省文件。下例保證了輸出的次序:
1 : #!/usr/local/bin/perl 2 : 3 : open (STDOUT, ">file1") || die ("open STDOUT failed"); 4 : open (STDERR, ">&STDOUT") || die ("open STDERR failed"); 5 : $| = 1; 6 : select (STDERR); 7 : $| = 1; 8 : print STDOUT ("line 1\n"); 9 : print STDERR ("line 2\n"); 10: close (STDOUT); 11: close (STDERR); 程序運行后,文件file1中內容為: line 1 line 2 第5行將$|賦成1,告訴Perl解釋器當前缺省文件不進行緩沖,因為未調用select,當前的缺省文件為重定向到文件file1的STDOUT。第6行將當前缺省文件設為STDERR,第7行又設置$|為1,關掉了重定向到file1的標準錯誤文件的緩沖。由于STDOUT和STDERR的緩沖均被關掉,向其的輸出立刻被寫到文件中,因此line 1出現在第一行。 4)指定讀寫權限 打開一個既可讀又可寫的文件方法是在文件名前加上"+>",如下: open (READWRITE, "+>file1"); 此語句打開既可讀又可寫的文件file1,即可以重寫其中的內容。文件讀寫操作最好與庫函數seek和tell一起使用,這樣可以跳到文件任何一點。 注:也可用前綴"+<"指定可讀寫權限。 5)close函數 用于關閉打開的文件。當用close關閉管道,即重定向的命令時,程序等待重定向的命令結束,如: open (MYPIPE, "cat file*|"); close (MYPIPE); 當關閉此文件變量時,程序暫停運行,直到命令cat file*運行完畢。 6)print, printf和write函數 print是這三個函數中最簡單的,它向指定的文件輸出,如果未指定,則輸出到當前缺省文件中,如: print ("Hello, there!\n"); print OUTFILE ("Hello, there!\n"); 第一句輸出到當前缺省文件中,若未調用select,則為STDOUT。第二句輸出到由文件變量OUTFILE指定的文件中。 printf函數先格式化字符串再輸出到指定文件或當前缺省文件中,如: printf OUTFILE (“You owe me %8.2f", $owing); 此語句取出變量$owing的值并替換掉串中的%8.2f,%8.2f是域格式的例子,把$owing的值看作浮點數。 write函數使用輸出格式把信息輸出到文件中,如: select (OUTFILE); $~ = "MYFORMAT"; write; 關于printf和write,詳見《第x章 格式化輸出》。 7)select函數 select函數將通過參數傳遞的文件變量指定為新的當前缺省文件,如: select (MYFILE); 這樣,MYFILE就成了當前缺省文件,當對print、write和printf的調用未指定文件時,就輸出到MYFILE中。 8)eof函數 eof函數查看最后一次讀文件操作是否為文件最后一個記錄,如果是,則返回非零值,如果文件還有內容,返回零。 一般情況下,對eof的調用不加括號,因為eof和eof()是等效的,但與<>操作符一起使用時,eof和eof()就不同了。現在我們來創建兩個文件,分別叫做file1和file2。file1的內容為: This is a line from the first file. Here is the last line of the first file. file2的內容為: This is a line from the second and last file. Here is the last line of the last file. 下面就來看一下eof和eof()的區別,第一個程序為:
1: #!/usr/local/bin/perl 2: 3: while ($line = <>) { 4: print ($line); 5: if (eof) { 6: print ("-- end of current file --\n"); 7: } 8: }
|