对于 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/
各自媒体平台均可搜寻【硬核项目经理】