發新話題

Perl小技巧:文件操作

Perl小技巧:文件操作

複製內容到剪貼板
代碼:
opendirDIR,$path;@arr1=readdirDIR;@arr2=grep{-T"$path$_"}@arr1;#textfilesonly@arr3=grep{!-d"$path$_"}@arr1;#nodirectories@arr4=grep{-s"$path$_"<1024}@arr1;#lessthan1K
代碼解釋:假如被測試的目錄項是一個文本文件,那麼-T文件操作符就會返回真。其實針對目錄項的測試操作還有很多。(註:文件和目錄在系統中都是以目錄項的形式來管理的,所以要區別一個目錄項指向的是一個文件還是一個目錄需要相應的操作符)。注意上面的readdir函數返回指定目錄下的所有目錄項。因為在grep函數中對目錄項的測試需要文件的完全路徑,所以我們把$PATH(存儲了目錄項的部分路徑)和$_(存儲了目錄項的名字)中的內容聯合起來得到文件的完全路徑*對目錄進行遞歸搜索*
複製內容到剪貼板
代碼:
useFile::Find;find(&handleFind,'imac:documents:code');subhandleFind{my$foundFile=$File::Find::name;print"$foundFilen"if($foundFile=~/.html?$/i);}
RESULT:imac:documents:code:index.htmlimac:documents:code:perl:example.
HTM運行結果:代碼討論:那些工作於Unix系統的Perl程序員可以非常簡便的利用UNIX上提供的工具來完成許多日常的工作,比如遞歸的列出指定目錄下的所有目錄項(也就是列出指定目錄及指定目錄子目錄下的所有目錄項目)。然而Perl的一個最大的特徵就是可以運行於很多的平台上。所以如果你碰巧工作在一個非UNIX的平台,或者如果你雖工作在UNIX平台,但不喜歡使用系統工具寫腳本,你可以選擇Perl。要完成這些巧妙的工作,你需要使用perl中的File:Find模塊。當你加載了這個模塊的時候,你就可以使用其中的find子函數,在調用這個函數的時候,需要帶參數:第一個參數是一個函數的引用,這個函數由你自己建立,每次一個文件被找到的時候,它都會運行。接下來的一個參數是一串你想要搜索的路徑。我寫的這個示例腳本是運行在MacintoshOS8.x系統上的,所以我使用了Mac系統的路徑分隔符:。如果是在Windows,你可以用反斜槓,如果是在Unix系統則是正斜槓(至於在Amiga系統上用什麼我就不知道了)。總之,find函數將會在每次找到一個文件的時候調用你給出的子函數,而且會對子目錄進行查找。在我的handledfind子函數中,我通過這個模塊特定變量$File::Find::name來獲得每次find找到的文件名。然後,就可以對該文件執行任何你想的測試,在上面的例子中,我們輸出有.html的擴展名文件名。*文件讀操作**一次讀入整個文件內容。
複製內容到剪貼板
代碼:
openFH,"<anthem";$/=undef;$slurp=;print$slurp;
運行結果:一下就顯示了所有的文件內容,此刻你應該非常的自豪。代碼討論:尖括號<>對文件句柄進行操作,在標量上下文中它將返回文件的下一條記錄,在數組上下文中它將返回所有的記錄。在默認的情況下,文件中的記錄被認為是由換行符分開(例如回車或其他代表新行開始的字符)。你可以重新設定這個默認的分隔符,然後Perl將會以你指定的分隔符為準來替代換行符。全局變量$/裡存儲了輸入文件的分隔符,如果你把$/的值設置為undef,那麼Perl將會認為整個文件是一條記錄(因為此刻已經沒有文件分隔符了)。牢記$/是全局變量,千萬不要在腳本的其他地方不經意的改變它,這個錯誤將很難被發現。你可能會問,我們能否不改變$/,而採用把文件的所有記錄讀到一個數組中,然後把數組聯合成一個很長的字符串(比如$slurp=join("",);)的方法實現一次讀入文件。當然這也是一個有效的解決辦法,但是你會發現它很慢,是否選用它取決你的應用,取決於你是否關心運行速度。*賦值**把一個文件句柄賦給另一個文件句柄*
複製內容到剪貼板
代碼:
open(MYOUT,">bottle.txt");*STDOUT=*MYOUT;print"message";
運行結果:文本文件bottle.txt現在包含message字符串。代碼討論:以前可能你配合使用過Print函數和文件句柄,但是你是否知道就算你沒有使用文件句柄,Perl也默認你在使用一個稱為STDOUT的句柄?C程序員知道STDOUT代表標準輸出,也就是通常的屏幕,或終端窗口(或者是CGI程序的輸出端-瀏覽器)。在這裡我們完成的工作是創建我們自己的文件句柄,它指向一個給定的文件,然後我們做了一件比較鬼的工作,使用*前綴把STDOUT轉換為typeglob類型。Typeglob類型的數據可以有別名,這樣一個變量可能會指向另一個其他名字的變量。上面第二行代碼使STDOUT指向MYOUT變量。所以執行print操作時的默認輸出對象也就成為了我們創建的文件句柄。*同時向兩個文件句柄執行寫操作*
複製內容到剪貼板
代碼:
useIO::Tee;$tee=IO::Tee->new(">>debuglog.txt",*STDOUT);print$tee"anerrorocurredon".scalar(localtime)."n";
運行結果:anerrorocurredonFriFeb2321:44:202001代碼討論:如果,由於種種原因你想要同時向兩個位置寫入同一個字符串,這和UNIX下的tee工具的用途一樣。即使你不是工作在Unix平台上,Perl也通過Tee模塊為你提供這個功能。Tee模塊可以在CPAN下載,你應該把它安裝到Perl的IO庫文件夾中。Tee模塊以OOP方式編寫,所以使用它之前你應該首先使用它的new方法來創建一個Tee對象,整個過程需要兩個參數,每個參數既可以是代表文件句柄的字符串,也可以是一個對已打開的文件句柄的引用。在上面的例子中,我們用一個字符串來代表一個以附加模式打開的文件句柄,它指向名為debuglog.txt的文件,另一個參數是系統內置的文件句柄STDOUT,整個句柄是系統自動創建的,print函數默認情況對它進行操作。為了得到一個文件句柄的引用我們需要對一個typeglob類型的數據使用反斜槓。Typeglob可以代表任何已命名的某個變量,不論它是數組,散列還是標量等。使用*很有必要,因為文件句柄自己沒有前綴符號。new操作符返回Tee類的一個實例對象,然後我們把整個實例賦給$tee標量。現在,無論什麼時候我們向$tee進行寫入操作,我們都同時向兩個位置進行寫操作。*更多文件操作。。。**從一個文件的完全路徑中找出它的名字*
複製內容到剪貼板
代碼:
useFile::Basename;$path="/docs/sitecircus.com/html/tricks/trick.of.the.week.html";$basename=basename($path,".html");print$basename;
運行結果:trick.of.the.week代碼討論:好了,成功了。問題是要找出文件的名字,要不帶任何路徑前綴,不帶任何擴展名。File::Basename模塊可以使這很容易實現,我們只需要把文件的完全路徑還有要剔除的擴展名傳給它。上面的path變量是文件的完全路徑,注意文件分隔符是/,這個字符很特殊,因為它是操作系統的保留字符。這裡你不能在文件名裡使用系統的分隔符。你應該知道當今流行的操作系統都使用自己獨特的文件分隔符:Unix使用/,Windows使用,Macintosh使用:(順便說一下,在Windows上的Perl腳本中,你既可以使用也可以使用/作為文件分隔符,Perl的解釋器能理解你的意思)。File::Basename,當然,能正確在完全路徑中找到文件名,不論時在什麼系統下。*改變文件的所有者*
複製內容到剪貼板
代碼:
($uid,$gid)=(getpwnam($username))[2,3]ordie"$usernotinpasswdfile";chown($uid,$gid,$file)orwarn"couldn'tchown$file.";
運行結果:無輸出代碼討論:有的時候,你可能知道一個用戶名,而你想用這個用戶名做些事,比如改變一個文件的所有者。但是不幸的是,Perl的chown命令不能接受用戶名作為參數,但是可以接受一對數字:userid和groupid。雖然有這些不便之處,Perl並沒有讓我們陷入困境,我們可以把用戶名作為getpwnam函數的參數,獲得一個數組,裡面包含了用戶名對應的userid和groupid,分別對應著數組裡的第二和第三個元素。

TOP

發新話題

本站所有圖文均屬網友發表,僅代表作者的觀點與本站無關,如有侵權請通知版主會盡快刪除。