三篇Perl IO基础类文章:html
不管是哪一种高级编程语言,都提供了较底层的操做系统层IO能力,也提供了更高层次的封装来实现语言级别的IO能力。编程
像文件描述符这种东西,是属于操做系统层的,比较底层,它是操做系统负责管理的资源。对于Perl来讲,文件句柄是Perl提供的比文件描述符更上一层的Perl IO层次的东西,文件句柄直接指向文件描述符(非一一对应关系,能够多个文件句柄指向同一个文件描述符),可是文件句柄层到文件描述符层的中间有一些由Perl IO提供的特性,毕竟封装了底层就要比底层功能更丰富、操做更方便,好比IO Buffer是属于Perl IO层的。编程语言
以上是IO全局上的概念,先了解便可,后面的文章会对其进行解释。这里先了解下Perl提供的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
提供了不少文件句柄类的通用操做,好比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::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_RDONLY
、O_CREAT
等。
它们之间的对应关系以下:
不难发现,O_RDONLY
、O_WRONLY
或O_RDWR
是三个基本的模式,任何一种模式都至少指定它们中的一个。
IO::File
还支持指定binmode来支持二进制读、写操做。详细内容参见perldoc -f binmode
。
最后,IO::File
的new_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):更多文件句柄模式。