Perl IO:簡介和經常使用IO模塊

三篇Perl IO基礎類文章:html

IO對象和IO::Module家族模塊

不管是哪一種高級編程語言,都提供了較底層的操做系統層IO能力,也提供了更高層次的封裝來實現語言級別的IO能力。編程

像文件描述符這種東西,是屬於操做系統層的,比較底層,它是操做系統負責管理的資源。對於Perl來講,文件句柄是Perl提供的比文件描述符更上一層的Perl IO層次的東西,文件句柄直接指向文件描述符(非一一對應關係,能夠多個文件句柄指向同一個文件描述符),可是文件句柄層到文件描述符層的中間有一些由Perl IO提供的特性,畢竟封裝了底層就要比底層功能更豐富、操做更方便,好比IO Buffer是屬於Perl IO層的編程語言

以上是IO全局上的概念,先了解便可,後面的文章會對其進行解釋。這裏先了解下Perl提供的IO方面的東西:函數

  • sysFUNC:這類函數是操做系統層的IO操做,如sysread、sysopen、sysseek、syswrite等
  • open:打開文件句柄,根據給定參數的不一樣,以不一樣層次的方式打開文件句柄
  • IO::Module:Perl提供的面向對象的IO接口,簡化IO操做,包括:
    • IO::Handle:提供文件句柄類的通用接口
    • IO::File:提供文件操做類的通用接口
    • IO::Dir:提供目錄操做類的通用接口
    • IO::Pipe:提供管道類的接口
    • IO::Socket:提供套接字類的接口
    • IO::Seekable:爲IO對象提供基於Seek操做的接口
    • IO::Select:提供select系統調用的面向對象接口
    • IO::Poll:提供poll系統調用的面向對象接口
    • IO:將上面幾種模塊整合到了這一個模塊中

對於支持面向對象的語言來講,通常文件句柄都會被抽象成一個IO對象來簡化IO操做(對於Perl,就是變量類型的文件句柄),經過這個對象能夠直接跨模塊調用不一樣模塊中的方法。操作系統

例如,Perl中以變量方式提供open的文件句柄能夠建立一個IO對象,只要導入了IO::Handle模塊,這個IO對象就能自動使用IO::Handle模塊中的方法,而不須要再從IO::Handle建立一個IO對象。指針

use IO::Handle;

# IO對象: $fh
open my $fh, ">", "test.log" 
    or die "open failed: $!";

# 直接調用IO::Handler中的方法
$fh->autoflush(1);

# 調用IO::Handler中的print函數
$fh->print("hello world\n");

實際上,經過open、sysopen或者上述IO家族模塊的某些模塊均可以建立IO對象(文件句柄對象),其中IO家族的模塊能夠建立匿名文件句柄,匿名的文件句柄對象能夠在後續任何須要的時候經過open綁定到某個具體的文件上。例如:code

use IO::Handle;
my $fh = IO::Handle->new();
open $fh, "file.txt" or die "open failed: $!";

# 等價於
open my $fh, "file.txt" or die "open failed: $!";

另外須要注意的是,本身經過open建立的裸文件句柄(即非變量類型的文件句柄)不是文件句柄對象,就像本身建立了一個LOG句柄,它沒法直接使用LOG->autoflush(1);htm

關於open相關的介紹,參見前面列出的基礎文章,關於操做系統層IO的sysFUNC函數,在後面以單獨的文章介紹。因此,這裏先介紹IO::家族的部分模塊。對象

IO::Handle簡介

IO::Handle提供了不少文件句柄類的通用操做,好比new()建立匿名的文件句柄對象,autoflush()函數設置自動刷新(即替代select FH;$| = 1;),等等。它也是全部IO家族模塊的基本組成模塊,並且通常不會直接使用IO::Handle來建立IO對象,而是經過其它IO模塊建立IO對象而後繼承這個模塊裏的方法。blog

例如,new()建立匿名文件句柄:

my $fh = IO::Handle->new();

IO::Handle提供了不少基礎操做,能夠查看perldoc手冊perldoc IO::Handle瞭解其屬性,在後面的內容或文章中會逐漸介紹其中的部分功能。

IO::File

該模塊提供了操做文件的通用接口,主要是以不一樣模式打開文件句柄的方法,而其它操做數據的方法都從IO::Handle中繼承。

先看例子:

use IO::File;

# 先建立匿名句柄,再open打開
$fh = IO::File->new();
if ($fh->open("< file")) {
    print <$fh>;
    $fh->close;
}

# 直接以單個參數方式建立並打開文件句柄
$fh = IO::File->new("> file");
if (defined $fh) {
    print $fh "bar\n";
    $fh->close;
}
 
# 直接以兩個參數方式建立並打開文件句柄
$fh = IO::File->new("file", "r");
if (defined $fh) {
    print <$fh>;
    undef $fh;     # 將自動關閉文件句柄
}                  # 等價於出了做用域範圍

# 直接以flag的方式建立並打開文件句柄
$fh = IO::File->new("file", O_WRONLY|O_APPEND);
if (defined $fh) {
    print $fh "corge\n";

    $pos = $fh->getpos;
    $fh->setpos($pos);
 
    undef $fh;       # automatically closes the file
}

autoflush STDOUT 1;

關於IO::File模塊中的new和open方法:

new([FILENAME [,MODE [,PERMS]]])
open(FILENAME [,MODE [,PERMS]])
open(FILENAME, IOLAYERS)

new()方法和open()方法都能建立並打開文件句柄,當new()沒有參數時,表示建立一個匿名句柄,當有任何參數時,都將調用open並傳遞參數給open。

open()能夠接收單個、兩個、三個參數,單參數的open()將直接調用內置open()函數。兩個或三個參數時,第一個參數是文件名(能夠包含特殊符號),第二個參數是open的模式。

若是open接收到了相似於> +< >>等方式的模式時,或者接收到了ANSI C fopen()的字符串格式的模式w r+ a等,它將調用內置open()函數並自動保護好一些特殊符號以避免出錯。

若是open接收到了數值格式的模式,則調用sysopen()函數並傳遞數值模式給它,例如0666。

若是open中包含了:符號,則將全部3個參數都傳遞給3參數方式的內置open()函數。

open還支持Fcntl模塊中定義的O_XXX模式,例如O_RDONLYO_CREAT等。

它們之間的對應關係以下:

不難發現,O_RDONLYO_WRONLYO_RDWR是三個基本的模式,任何一種模式都至少指定它們中的一個。

IO::File還支持指定binmode來支持二進制讀、寫操做。詳細內容參見perldoc -f binmode

最後,IO::Filenew_tmpfile()方法能夠在/tmp目錄下建立並打開這個臨時文件,這個臨時文件和普通意義上的臨時文件有些不一樣,它是直接建立一個文件,而後一直保持打開,並當即刪除它,也就是說它是匿名的文件。這樣在操做系統上就看不到這個文件,可是卻能夠對這個臨時文件進行IO,從而實現真正意義上的臨時文件。若是建立成功,它返回IO對象,不然銷燬IO對象。

顯然,這個建立就被刪除的臨時文件只有在同時提供讀、寫能力時纔有意義,只讀或者只寫是沒有意義的。

例如:

#!/usr/bin/perl
use strict;
use warnings;

use IO::Handle;
use IO::File;

# 建立臨時文件
my $tmp_file = IO::File->new_tmpfile();
$tmp_file->autoflush(1);

# 這個臨時文件已經被刪除了
system("lsof -n -p $$ | grep 'deleted'");

# 寫入一點數據
$tmp_file->say("Hello World1");
$tmp_file->say("Hello World2");
$tmp_file->say("Hello World3");
$tmp_file->say("Hello World4");

# 指針移動到臨時文件的頭部來讀取數據
seek($tmp_file, 0, 0);

while(<$tmp_file>){
    print "Reading from tmpfile: $_";
}

執行結果:

perl  22583 root  3u  REG  0,2  0  2533274790579481 /tmp/PerlIO_ns1KST (deleted)
Reading from tmpfile: Hello World1
Reading from tmpfile: Hello World2
Reading from tmpfile: Hello World3
Reading from tmpfile: Hello World4

其實內置函數open()或者IO::File的open()方法也能建立一樣的臨時文件,只須要將open()的文件名參數指定爲undef便可,因爲指定了undef文件名,因此open()只能是三參數模式的。

例如:

open LOG, "+<", undef or die "open failed: $!";

open()內置函數建立臨時文件的示例參見:Perl的IO操做(2):更多文件句柄模式

相關文章
相關標籤/搜索