三篇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对象。

  1. use IO::Handle;
  2. # IO对象: $fh
  3. open my $fh, ">", "test.log"
  4. or die "open failed: $!";
  5. # 直接调用IO::Handler中的方法
  6. $fh->autoflush(1);
  7. # 调用IO::Handler中的print函数
  8. $fh->print("hello world\n");

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

  1. use IO::Handle;
  2. my $fh = IO::Handle->new();
  3. open $fh, "file.txt" or die "open failed: $!";
  4. # 等价于
  5. 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()创建匿名文件句柄:

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

IO::Handle提供了很多基础操作,可以查看perldoc手册perldoc IO::Handle了解其属性,在后面的内容或文章中会逐渐介绍其中的部分功能。

IO::File

该模块提供了操作文件的通用接口,主要是以不同模式打开文件句柄的方法,而其它操作数据的方法都从IO::Handle中继承。

先看例子:

  1. use IO::File;
  2. # 先创建匿名句柄,再open打开
  3. $fh = IO::File->new();
  4. if ($fh->open("< file")) {
  5. print <$fh>;
  6. $fh->close;
  7. }
  8. # 直接以单个参数方式创建并打开文件句柄
  9. $fh = IO::File->new("> file");
  10. if (defined $fh) {
  11. print $fh "bar\n";
  12. $fh->close;
  13. }
  14. # 直接以两个参数方式创建并打开文件句柄
  15. $fh = IO::File->new("file", "r");
  16. if (defined $fh) {
  17. print <$fh>;
  18. undef $fh; # 将自动关闭文件句柄
  19. } # 等价于出了作用域范围
  20. # 直接以flag的方式创建并打开文件句柄
  21. $fh = IO::File->new("file", O_WRONLY|O_APPEND);
  22. if (defined $fh) {
  23. print $fh "corge\n";
  24. $pos = $fh->getpos;
  25. $fh->setpos($pos);
  26. undef $fh; # automatically closes the file
  27. }
  28. autoflush STDOUT 1;

关于IO::File模块中的new和open方法:

  1. new([FILENAME [,MODE [,PERMS]]])
  2. open(FILENAME [,MODE [,PERMS]])
  3. 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对象。

显然,这个创建就被删除的临时文件只有在同时提供读、写能力时才有意义,只读或者只写是没有意义的。

例如:

  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use IO::Handle;
  5. use IO::File;
  6. # 创建临时文件
  7. my $tmp_file = IO::File->new_tmpfile();
  8. $tmp_file->autoflush(1);
  9. # 这个临时文件已经被删除了
  10. system("lsof -n -p $$ | grep 'deleted'");
  11. # 写入一点数据
  12. $tmp_file->say("Hello World1");
  13. $tmp_file->say("Hello World2");
  14. $tmp_file->say("Hello World3");
  15. $tmp_file->say("Hello World4");
  16. # 指针移动到临时文件的头部来读取数据
  17. seek($tmp_file, 0, 0);
  18. while(<$tmp_file>){
  19. print "Reading from tmpfile: $_";
  20. }

执行结果:

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

其实内置函数open()或者IO::File的open()方法也能创建同样的临时文件,只需要将open()的文件名参数指定为undef即可,由于指定了undef文件名,所以open()只能是三参数模式的。

例如:

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

open()内置函数创建临时文件的示例参见:Perl的IO操作(2):更多文件句柄模式

Perl IO:简介和常用IO模块的更多相关文章

  1. java nio(non-blocking io)简介及和io

    在 Java1.4之前的I/O系统中,提供的都是面向流的I/O系统,系统一次一个字节地处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节 的数据,面向流的I/O速度非常慢,而在Java 1 ...

  2. python 全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...

  3. {python之IO多路复用} IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) IO模型比较分析 selectors模块

    python之IO多路复用 阅读目录 一 IO模型介绍 二 阻塞IO(blocking IO) 三 非阻塞IO(non-blocking IO) 四 多路复用IO(IO multiplexing) 五 ...

  4. (IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    参考博客: https://www.cnblogs.com/xiao987334176/p/9056511.html 内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yi ...

  5. python全栈开发,Day44(IO模型介绍,阻塞IO,非阻塞IO,多路复用IO,异步IO,IO模型比较分析,selectors模块,垃圾回收机制)

    昨日内容回顾 协程实际上是一个线程,执行了多个任务,遇到IO就切换 切换,可以使用yield,greenlet 遇到IO gevent: 检测到IO,能够使用greenlet实现自动切换,规避了IO阻 ...

  6. JAVA基础知识之IO——Java IO体系及常用类

    Java IO体系 个人觉得可以用"字节流操作类和字符流操作类组成了Java IO体系"来高度概括Java IO体系. 借用几张网络图片来说明(图片来自 http://blog.c ...

  7. 并发编程之IO模型比较和Selectors模块

    主要内容: 一.IO模型比较分析 二.selectors模块 1️⃣ IO模型比较分析 1.前情回顾: 上一小节中,我们已经分别介绍过了IO模型的四个模块,那么我想大多数都会和我一样好奇, 阻塞IO和 ...

  8. Java IO简介

    -------------siwuxie095                 Java IO简介:     IO 也写作"I/O",可理解为 In 和 Out,即 输入 与 输出 ...

  9. IO流——常用IO流详解

    1:字节流 字节流:用于处理以字节为单位的二进制文件(如音乐,图片等) InputStream 是抽象类 它的对应子类FileInputStream可以被实例化 构造方法: FileInputStre ...

随机推荐

  1. 开发中少不了的Fun -- 获取地址栏URL参数

    假设这是一个url地址 http://localhost:8080/a/b/c?a=1&b=2#abc,里面包含的部分: protocol: 'http:', // 协议 host: 'loc ...

  2. spring ref &history&design philosophy

    Spring Framework Overview Spring是开发java application的通用框架,分为多个模块(modules),核心是core container,包括configu ...

  3. Vue(三十一)轮播组件

    直接上源码 (1)组件文件 Carousel.vue <template> <div class="carousel-component"> <div ...

  4. Katalon Studio之请求响应中文乱码解决方法

    最近在用Katalon做接口测试过程中发现请求响应消息中返回的中文均为乱码,这是因为我们使用的系统环境在初始安装时选择的中文简体,导致windows系统默认编码格式为GBK,但是KS的编码格式是UTF ...

  5. vue单页面应用刷新网页后vuex的state数据丢失的解决方案

    1. 产生原因其实很简单,因为store里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值. 2. 解决思路一种是state里的数据全部是通过请求 ...

  6. 小程序组件化框架 WePY 在性能调优上做出的探究

    作者:龚澄 导语 性能调优是一个亘古不变的话题,无论是在传统H5上还是小程序中.因为实现机制不同,可能导致传统H5中的某些优化方式在小程序上并不适用.因此必须另开辟蹊径找出适合小程序的调估方式. 本文 ...

  7. 在 ubuntu 中愉快的安装 Jenkins

    这篇文章详细的记录了在 ubuntu 中安装 Jenkins 的一步又一步,因为找了很多 Linux 下安装 Jenkins 的教程,不是很满意 所以决定自己写一篇以备后用(终于让我找到了Java 不 ...

  8. MapReduce计算模型的优化

    MapReduce 计算模型的优化涉及了方方面面的内容,但是主要集中在两个方面:一是计算性能方面的优化:二是I/O操作方面的优化.这其中,又包含六个方面的内容. 1.任务调度 任务调度是Hadoop中 ...

  9. FFmpeg 结构体学习(一): AVFormatContext 分析

    在 FFmpeg 学习(六):FFmpeg 核心模块 libavformat 与 libavcodec 分析 中,我们分析了FFmpeg中最重要的两个模块以及重要的结构体之间的关系. 后面的文章,我们 ...

  10. CS231n 第一次作业KNN中本地CIFAR10数据集的载入

    一.问题描述 网上绝大多数作业参考都是在jupyter下运行的,数据集载入过程一般如下: from cs231n.data_utils import load_CIFAR10 #导入数据集,并打印出数 ...