关于 PHP 的文件操作,我们也将是通过一系列的文章来进行学习。今天我们先学习的是一个很少人使用过,甚至很多人根本不知道的扩展,它与我们日常的文件操作有些许的不同。不过这些差别并不是我们肉眼所能直观看到的,主要还是在于业务的需求与性能的平衡。

什么是Direct IO

Direct IO 其实是 Linux 操作系统中的一个概念。它的意思是直接操作文件流,为什么说是直接呢?其实在我们的操作系统进行文件操作的时候,并不是马上直接就在磁盘上进行文件的读写,中间还有一层页缓存。既然是缓存,那么它当然是会带来一定的性能提升,但这也并不是完全绝对的。而直接操作就是忽略掉这一层的缓存操作,直接对磁盘上的文件进行读写。我们都知道,磁盘,即使是固态硬盘,它和 CPU 以及内存的处理速度之间都是有着巨大的落差的,默认的页缓存就是用来弥补这种差距。但是页缓存会加大 CPU 的运算操作以及占用内存,而直接操作则不会有这种问题,但是相对来说,它的速度并不能和带缓存的文件读取操作相媲美。

以上是关于 Direct IO 的一个简单的理解,更详尽的解释大家可以参考文末参考文档中第二条链接的内容并进行深入的学习。在 PHP 中,我们直接在 PECL 下载 Direct IO 扩展就可以按照扩展的正常安装方式进行安装使用。

创建写入文件

既然是文件操作,那么我们首先还是来创建和写入一些文件数据。

$fd = dio_open("./test", O_RDWR | O_CREAT);

echo dio_write($fd, "This is Test.I'm ZyBlog.Show me the money4i"), PHP_EOL;
// 43 print_r(dio_stat($fd));
// Array
// (
// [device] => 64768
// [inode] => 652548
// [mode] => 35432
// [nlink] => 1
// [uid] => 0
// [gid] => 0
// [device_type] => 0
// [size] => 43
// [block_size] => 4096
// [blocks] => 8
// [atime] => 1602643459
// [mtime] => 1602656963
// [ctime] => 1602656963
// ) dio_close($fd);

和 f 系列的函数类似,我们需要使用一个 dio_open() 函数来打开一个文件,O_RDWR | O_CREAT 参数的意思是打开一个可读写文件,并且如果文件不存在的话,创建它。这两个常量是与 Linux 中相关的直接操作文件的常量对应的,在文末的链接中也可以看到关于这些常量的解释。

写入操作也是同样的使用一个 dio_write() 就能够完成,它返回的内容是写入的内容长度,这里我们写入了 43 个字符。

dio_stat() 是返回当前文件句柄的一些信息,我们可以看到设备号 device 、uid 、 gid 、 atime 、 mtime 等一些信息,它们和我们在 Linux 中能够看到的信息类似,其实就是这个文件的一些简单的信息。

读取文件

读取文件使用非常简单的使用一个函数就可以完成。

$fd = dio_open("./test", O_RDWR | O_CREAT);

echo dio_read($fd), PHP_EOL;
// This is Test.I'm ZyBlog.Show me the money4i dio_close($fd);

dio_read() 函数还包含另外一个参数,可以按指定的字节长度读取内容,这个在后面我们还会看到相关的示例。

文件操作

在文件的读取过程中,我们有可能只需要读取一部分的内容,或者从某一位置开始读取文件内容,下面的操作函数就是针对这两个方面进行操作的。

$fd = dio_open("./test", O_RDWR | O_CREAT);

var_dump(dio_truncate ($fd , 20));
// bool(true)
echo dio_read($fd), PHP_EOL;
// This is Test.I'm ZyB dio_seek($fd, 3); echo dio_read($fd), PHP_EOL;
// s is Test.I'm ZyB dio_close($fd);

其实从名称就可以看出 dio_truncate() 就是用于截断文件内容的。在这里我们从第 20 个字符进行截断,然后再使用 dio_read() 读取的内容就只是前 20 个字符的内容了。

dio_seek() 则是指定从哪一个字符开始读取内容,我们指定开始字符位置为 3 之后,前面三个字符就不会被读取到了。需要注意的是,dio_truncate() 会修改原始文件的内容,而 dio_seek() 则不会修改。

其它设置

$fd = dio_open('./test', O_RDWR | O_NOCTTY | O_NONBLOCK);

dio_fcntl($fd, F_SETFL, O_SYNC);

dio_tcsetattr($fd, array(
'baud' => 9600,
'bits' => 8,
'stop' => 1,
'parity' => 0
)); while (($data = dio_read($fd, 4))!=false) {
echo $data, PHP_EOL;
}
// This
// is
// Test
// .I'm
// ZyB dio_close($fd);

dio_fcntl() 函数是调用的 c 函数库中的 fcntl 函数,目的是对文件描述符执行指定的一些操作,这个操作也是以一些常量进行固定的,在这里我们使用的是 F_SETFL ,它的意思是将文件描述符标志设置为指定的值,这个 O_SYNC 表示的是如果设置了这个描述符,则对该文件的写操盘会等到数据被写到磁盘上才结束。当然,这个函数还可以设置很多别的操作符,大家可以参考 PHP 的官方文档进行深入的学习。

dio_tcsetattr() 用于设置打开文件的终端属性和波特率。 baud 表示的就是波特率,bits 表示的是位,stop 表示的是停止位,parity 表示的是奇偶校验位。关于这方面的内容需要 《计算机组成原理》 及 《操作系统》 中的一些知识,我也并不十分地清楚,所以也就不详细的解释了。从这里就可以看出,大学课堂上的那些基础课程真的是非常地重要,相信好好学过这些专业基础课程的同学一定能马上明白这个函数的作用。

最后,我们在 dio_read() 中使用了第二个参数来根据字节长度读取文件内容,可以看到读取出来的内容是一段一段的以 4 个字符长度为单位的输出。

总结

函数的学习还是比较简单的,核心的还是要知道这个扩展在什么业务场景下更适合使用。在文章开头的介绍中我们已经说明了直接操作文件与普通文件操作的一些区别,在自缓存应用或者需要传输非常大的数据时,直接操作对于 CPU 和 内存 更加地友好。而其它情况,我们还是使用系统默认的文件操作方式就可以了。其实在大部分情况下,我们基本看不出来它们的显著区别。所以在实际应用中,还是那句话,结合业务实际情况,选择最佳的方案。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/4.PHP中DirectIO直操作文件扩展的使用.php

参考文档:

https://www.php.net/manual/zh/book.dio.php

https://www.ibm.com/developerworks/cn/linux/l-cn-directio/

关注公众号:【硬核项目经理】获取最新文章

添加微信/QQ好友:【xiaoyuezigonggong/149844827】免费得PHP、项目管理学习资料

知乎、公众号、抖音、头条搜索【硬核项目经理】

B站ID:482780532

PHP中DirectIO直操作文件扩展的使用的更多相关文章

  1. 如何去掉drwxr-xr-x@中的@符号Linux文件扩展信息

    如何去掉drwxr-xr-x@中的@符号Linux文件扩展信息ls -lart drwxrwxrwx@ 10 rlanffy staff 340B 3 6 2015 files-rwxrwxrwx@ ...

  2. python中OS模块操作文件和目录

    在python中执行和操作目录和文件的操作是通过内置的python OS模块封装的函数实现的. 首先导入模块,并查看操作系统的类型: >>> import os os.name # ...

  3. Linux中一些约定俗成的文件扩展名

    注:Linux中的所有内容均以文件的形式保存,但不依靠扩展名区分文件类型(根据权限区分),约定俗成的文件扩展名是为了方便管理员对文件进行区分 压缩包:“*.gz”.“*.bz2”.“*.tar.bz2 ...

  4. 在bash shell中使用getfattr查看文件扩展属性

    getfattr用法 用于获取文件扩展属性,返回一系列键值对,参考Linux Man Page. 常用OPTIONS -n name, --name=name Dump the value of th ...

  5. Python中通过open()操作文件时的文件中文名乱码问题

    最近在用Python进行文件操作的时候,遇到创建中文文件名的乱码问题. Python默认是不支持中文的,一般我们在程序的开头加上#-*-coding:utf-8-*-来解决这个问题,但是在我用open ...

  6. python中使用with操作文件,为什么不需要手动关闭?

    python中的with关键字,它是用来启动一个对象的上下文管理器的.它的原理是,当我们使用with去通过open打开文件的时候,它会触发文件对象的上下文管理器, 当with中的代码结束完成之后,去自 ...

  7. 在PHP中操作文件的扩展属性

    在操作系统的文件中,还存在着一种我们可以自己定义的文件属性.这些属性不是保存在文件内容中,也不是直接可以通过 ls -al 所能看到的内容.它们可以将一个键值对信息永久得关联到文件上,一般现在的 Li ...

  8. Java中创建操作文件和文件夹的工具类

    Java中创建操作文件和文件夹的工具类 FileUtils.java import java.io.BufferedInputStream; import java.io.BufferedOutput ...

  9. 对Aspose.Cells Excel文件操作的扩展

    工作中对Excel操作的需求很是常见,今天其他项目组的同事在进行Excel数据导入时,使用Aspose.Cells Excel 遇到了些问题. 刚好闲来不忙,回想自己用过的Excel文件操作,有NPO ...

随机推荐

  1. Golang语言系列-09-接口

    接口 接口的定义和实现 package main import "fmt" /* [接口] 接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现 ...

  2. 利用ST-LINK配合ST-LINK Utility 将bin文件下载到STM32的FLASH中

    文章目录 背景 1.连接ST-LINK V2与单片机 2.配置工程 3.配置ST-LINK Utility 4.烧录bin文件 背景 项目需求,要把字模文件导入到32中FLASH的指定地址,使用了ST ...

  3. NOIP 模拟 $20\; \rm 玩具$

    题解 \(by\;zj\varphi\) 一道概率与期望好题 对于一棵树,去掉根后所有子树就是一个森林,同理,一个森林加一个根就是一棵树 设 \(f_{i,j}\) 为有 \(i\) 个点的树,高度为 ...

  4. 题解 math

    传送门 赛时用一个奇怪的方法过掉了 首先\(b_i\)的有效范围是\([0, k-1]\) 发现不同的\(a_i*b_i\)会有很多重的 考虑把\(a_i\%k\),然后由小到大排序 按顺序扫,如果某 ...

  5. 最短路径 | 深入浅出Dijkstra算法(一)

    参考网址: https://www.jianshu.com/p/8b3cdca55dc0 写在前面: 上次我们介绍了神奇的只有五行的 Floyd-Warshall 最短路算法,它可以方便的求得任意两点 ...

  6. git 的指定参考教程

    https://www.runoob.com/git/git-create-repository.html

  7. Linux命令:ps -ef |grep java

    一.ps -ef |grep java 查看包含"java"的所有进程 二.涉及命令详解 ps命令将某个进程显示出来(是LINUX下最常用的也是非常强大的进程查看命令) grep命 ...

  8. ffmpeg 常用知识点收集

    ffmpeg 常用知识点收集 一.基础简介 FFmpeg是一个自由软件,可以运行音频和视频多种格式的录影.转换.流功能,包含了libavcodec ─这是一个用于多个项目中音频和视频的解码器库,以及l ...

  9. ubuntu 查看系统信息

    1.系统信息 uname -a 显示linux的内核版本和系统是多少位的:X86_64代表系统是64位的. Linux field-ubuntu-18 4.15.0-20-generic #21-Ub ...

  10. JDBC中的元数据——2.参数元数据

    package metadata; import java.sql.Connection; import java.sql.ParameterMetaData; import java.sql.Pre ...