自動目錄
對於檔案讀寫,PERL很容易就上手,我常用來同時處理上千個檔案,都在極短的時間內就能處理完。但PERL對檔案的支援內容很多,我粗分為幾個部分:
讀取檔案
寫入或添加內容
刪除
讀取二進位檔
更名
目錄操作
檔案測試
讀取檔案
無論是讀取或寫入,檔案處理的基本步驟就是
讀取內容或寫入資料
關閉檔案
先看範例,並分別說明如下:
open(FILE, 'file.txt') or die "$!"; while( defined( $line = <FILE> )){ print $line; } close(FILE);
開啟檔案
開啟使用open指令,第一個項目放入file handle,是一種檔案指標,名稱隨意,習慣上會用大寫來表示,不必加引號,就算有加也沒關係;
第二個項目放檔案的(路徑+)名稱。
如果開啟失敗,例如檔案不存在或權限錯誤,就會回傳 undef ,後面的操作就會失敗,所以要改成這樣:
這行
open(FILE, '\path\to\file.txt') or die "$!";
分成兩個部分,青底的如果不為真(undef)就會處理綠底的這部分,其中 die 會傾印後面的 "$!"並結束。
$!是PERL的特殊變數,意思是「錯誤訊息」。
這種"or die" 的寫法常會在PERL中看到,可說是正字標記。整句可看成:「如果無法開檔就印出錯誤訊息並結束。」
讀取內容
FILE是我設定的檔案處理指標,在取用時得用角刮號 '<>' 給包起來。
一次取一行,並將處理指標指到此行的下一個字元上,再執行一次時會取下一行,如果取不到資料,會回傳 undef
當我用 while 時就能取回所有的資料直到取不到為止。
關閉檔案
除非檔案處理指標重覆使用,可以省略這個步驟外,每次都記得關閉檔案。
寫入或添加內容
開啟檔案的open指令第二個項目前面如果加上一個符號 '>' 就代表「開啟以供寫入檔案」;加上符號 '>>' 就代表「開啟以供為入內容到檔案後端」。
如果要寫入的檔案不存在自動建立新檔,差別在於寫入時如果原檔案有內容直接會被清空;而添加的會加檔案的後面。
寫入
添加
寫入指定編碼 utf8,這兩者都可以
寫入內容的方式是使用印的
print FILE "要寫入的內容第二行\n";
也可以一次把陣列印進去
@line = ("line1", "line2");
print FILE @line;
把陣列一次印進去的方法在自己覆寫自己時很方便,但限制是檔案並不大的情況。例如以下範例,要把檔案 'file.html' 中的所有字串 'default.html' 改成 'index.php' 並儲存。
# 讀原檔 open(FILE, 'file.html') or die "$!"; @origin = <FILE>; close(FILE); # 寫入原檔 open(FILE, '> file.html') or die "$!"; foreach ( @origin ){ $_ =~ s/default\.html/index.php/g; } print FILE @origin; close(FILE);
第9行是要處理的部分,可依需求作修改,這樣子PERL 就能替我們作很多事,尤其是大量取代。
刪除檔案
使用 unlink 指令即可
讀取二進位檔
前面介紹的續取寫入方式如果未指定都是以純文字來處理,如果要用二進位方式來處理檔案,會加上一指令 binmode
來看範例讀取圖檔,這個範例把圖檔 pic.jpg 的每一個位元用十進位給印出來。
open(FILE, 'pic.jpg') or die "$!"; binmode(FILE); while( defined( $ch= getc(FILE))){ print ord($ch). " "; } close(FILE);
說明
第2行 binmode改為二進位模式
第3行 使用getc一個個讀取字元
第4行 使用ord把字元由ASCII表轉成10進位,這行也可以這樣改寫成十六進位表示:
printf("%02X ", ord($ch));
結果
137 80 78 71 13 10 26 10 0 0 0 13 73 72 68 82 0 0 0 150 0 0 0 150 8 6 0 0 0 60 1 113 226 0 0 0 4 103 65 77 65 0 0 177 142 124 251 81 147 0 0 0 32 99 72 82 77 0 0 135 15 0 0 140 15 0 0 253 82 0 0 129 64 0 0 125 121 0 0 233 139 0 0 60 229 0 0 25 204 115 60 133 119 0 0 0 6 98 75 71 68 0 255 0 255 0 255 160 189 167 147 0 0 0 9 111 70 70 115 0 0 0 0 0 0 0 54 0 83 54 39 187 0 0 0 9 112 72 89 115 0 0 14 196 0 0 14 196 1 149 43 14 27 0 0 0 7 116 73 77 69 7 224 10 22 10 22 49 165 131 145 251 0 0 0 9 118 112 65 103 0 0 0 150 0 0 1 3 0 244 2 113 163 0 0 68 133 73 68 65 84 120 218 237 189 119 152 28 213 149 254 255 185 85 213 185 123 114 206 154 81 206 9 161 128 16 65 128 200 24 227 0 182 193 54 11 235 200 218 94 123 215 203 207 235 93 127 189 193 187 235 245 174 215 1 99 147 131 13 38 8 147 17 81 72 66...以下略
更名
更名使用rename函數
rename('pic.jpg','picnew.jpg') or die "$!";
目錄也可以更名
目錄操作
和檔案操作一樣,目錄操作有以下的函數:
opendir 開啟目錄
readdir 讀取目錄內容
closedir 關閉目錄
rmdir 刪除目錄
mkdir 建立目錄
印出目錄的內容
直接由範例來解說,要印出指定目錄的內容
opendir( DIR, './') or die "$!"; while( defined( $onedir= readdir(DIR))){ print $onedir. "\n"; } closedir( DIR);
說明
第1行 開啟指定此檔所在的目錄
第3行 readdir是讀取目錄中項目的方法
結果
.
..
.bash_logout
.bash_profile
.bashrc
i.php
.mysql_history
.bash_history
file.txt
.viminfo
01.pl
_backup
.ssh
uca.cer
02.pl
.pki
由上面範例得知,無論是不是隱藏檔都會被印出來,並且照著某種神秘的順序印出?你也可以用下面這個方法挑出你想要的檔案類型:
@files = grep { /\.pl$/i } readdir(DIR);
closedir(DIR);
建立目錄
如果目錄不存在,則建立目錄
目錄建立一次只能建一層,例如上例中,你的目錄 path/to/ 要先存在
第二個參數0755是目錄的權限,千萬不能寫成755或是加了引號 "0755",結果會出乎意料。
刪除目錄
或加上括號
rmdir(path/to/dir);
rmdir 在PERL裡面非常的雞肋,因為只要目錄不是空的,刪除目錄就失敗並報錯:
Directory not empty
所以他的可用性很低,你可以使用use File::Path 中的rmtree來解決這個問題:
use File::Path;
rmtree path/to/dir or die $!;
前面讀取目錄清單的缺點是不知道哪個是檔案?哪個是目錄?因此要進行「檔案測試」。
檔案測試
使用簡單的檔案測試運算子就能進行檔案的測試,例如分出檔案、目錄、建立日期、大小、權限等。他的寫法是這樣
例如:
if(-e 'somefile.txt'){ print "檔案已存在"; } if(!-e 'somefile.txt'){ print "檔案不存在"; } if(-z 'somefile.txt'){ print "檔案大小為0,檔案不存在為假"; } if(-f 'somefile.txt'){ print "這是一個檔案"; } if(-d 'somename'){ print "這是一個目錄"; } print -s '01.pl'; # 檔案大小,無此檔回傳 undef if(-M 'somefile' > 7){ print "建立日期大於7天"; }
可使用的檔案測試運算子,請參考官網[1]
上面的例子常常被寫成後置表示法,再搭配unless的使用,這也是PERL的特色,例如檢測是否可讀的權限
print "可讀取" if -r 'somefile';
print "不可寫入" unless -w 'somefile';
下一篇談到資料庫的運用。
上一篇 19-模組的安裝和維護
回到目錄 01-撰寫第一隻PERL程式
下一篇 21- 使用資料庫
參考資料
[1] https://perldoc.perl.org/functions/-X.html