zoukankan      html  css  js  c++  java
  • Perl IO:简介和常用IO模块

    三篇Perl IO基础类文章:

    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
    ");
    

    实际上,通过open、sysopen或者上述IO家族模块的某些模块都可以创建IO对象(文件句柄对象),其中IO家族的模块可以创建匿名文件句柄,匿名的文件句柄对象可以在后续任何需要的时候通过open绑定到某个具体的文件上。例如:

    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);

    关于open相关的介绍,参见前面列出的基础文章,关于操作系统层IO的sysFUNC函数,在后面以单独的文章介绍。所以,这里先介绍IO::家族的部分模块。

    IO::Handle简介

    IO::Handle提供了很多文件句柄类的通用操作,比如new()创建匿名的文件句柄对象,autoflush()函数设置自动刷新(即替代select FH;$| = 1;),等等。它也是所有IO家族模块的基本组成模块,而且一般不会直接使用IO::Handle来创建IO对象,而是通过其它IO模块创建IO对象然后继承这个模块里的方法。

    例如,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
    ";
        $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
    ";
    
        $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):更多文件句柄模式

  • 相关阅读:
    java线程——三种创建线程的方式
    java线程——详解Callable、Future和FutureTask
    商品详情页系统的Servlet3异步化实践
    关于servlet3.0中的异步servlet
    Spring中线程池的应用
    Spring中@Async注解实现“方法”的异步调用
    高性能的关键:Spring MVC的异步模式
    SpringBoot+springmvc异步处理请求
    指定Qt程序运行的style,比如fusion(以前没见过QStyleFactory)
    Linux下获取arm的交叉编译工具链
  • 原文地址:https://www.cnblogs.com/f-ck-need-u/p/10442177.html
Copyright © 2011-2022 走看看