百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

PHP中的文件系统函数(三)

liebian365 2024-11-21 17:35 17 浏览 0 评论

总算来到我们最关心的部分了,也就是 f 相关函数的操作。基本上大部分的文件操作都是以今天学习的这些内容为基础的,话不多说,我们就一个一个的来学习学习吧。

文件读取

文件的读取其实非常简单,fopen() 打开句柄,fread() 读取内容,fclose() 关闭句柄,一套流程下来操作就完成了。

$f = fopen('./test.txt', 'r+');

while (!feof($f)) {
    $contents = fread($f, 4);
    echo $contents, PHP_EOL;
}
// Rain
//  is
// fall
// ing
// all
// arou
// nd,

// It f
// alls
//  on
// ……
// ……

fopen() 函数的第二个参数是我们可以操作的权限。这个大家应该不会陌生,w 就是可写,r 就是可读,r+ 就是读写方式打开并将文件指针指向文件头,a 是追加写入。

模式说明
'r'只读方式打开,将文件指针指向文件头。
'r+'读写方式打开,将文件指针指向文件头。
'w'写入方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
'w+'读写方式打开,将文件指针指向文件头并将文件大小截为零。如果文件不存在则尝试创建之。
'a'写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
'a+'读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建之。
'x'创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则 fopen() 调用失败并返回 FALSE,并生成一条 E_WARNING 级别的错误信息。如果文件不存在则尝试创建之。这和给 底层的 open(2) 系统调用指定 O_EXCL
'x+'创建并以读写方式打开,其他的行为和 'x' 一样。
'c'只打开文件进行写入。如果文件不存在,则创建该文件。如果它存在,它既不会被截断(与“w”相反),也不会导致对该函数的调用失败(与“x”一样)
'c+'打开文件进行读写;否则它的行为与“c”相同。

fread() 函数的第二个参数是每次要读取的字节数,可以看到在测试代码中我们是以 4 个字节为单位进行读取的,所以文件内容都是按 4 个字节分开的一行一行的输出的。feof() 用于判断当前文件的游标指针是否已经移动到末尾了。

游标操作

既然说到游标,那么我们就来看看游标相关的操作。

while (!feof($f)) {
    $contents = fread($f, 1024);
    echo $contents, PHP_EOL;
}
//

rewind($f);
while (!feof($f)) {
    $contents = fread($f, 1024);
    echo $contents, PHP_EOL;
}
// Rain is falling all around,
// It falls on field and tree,
// It rains on the umbrella here,
// And on the ships at sea.

当使用最上方的代码读取过一遍内容后,游标就已经到底了,这时候再次循环是无法读取文件内容的,需要使用 rewind() 函数将游标进行重置。

读取单个字符

rewind($f);
while (($c = fgetc($f)) !== false) {
    echo $c, PHP_EOL;
}
// R
// a
// i
// n

// i
// s

// f
// a
// ……
// ……

fgetc() 函数用于读取单个字符。这个函数就比较简单了,不过需要注意的是如果用它读取中文的话,效果就不行了,因为中文是一个字占 2 或 3 个字节,使用这个函数读取出来的将是乱码的内容,在后面我们会有示例。

读取一行

while (($c = fgets($f)) !== false) {
    echo $c, PHP_EOL;
}
// Rain is falling all around,

// It falls on field and tree,

// It rains on the umbrella here,

// And on the ships at sea.

fgets() 函数用于按行读取文件内容,这个函数也是比较常用的函数,大家不会陌生。

读取 csv 文件

// fgetcsv
$f = fopen('./csv_test.csv', 'r');
while (($c = fgetcsv($f)) !== false) {
    print_r($c);
}
// Array
// (
//     [0] => 49
//     [1] => 20
//     [2] => 0
//     [3] => 42
//     [4] => 5/10/2020 12:32:18
// )
// Array
// (
//     [0] => 50
//     [1] => 21
//     [2] => 0
//     [3] => 74
//     [4] => 5/10/2020 12:32:29
// )
// Array
// (
//     [0] => 51
//     [1] => 22
//     [2] => 0
//     [3] => 35.8
//     [4] => 5/10/2020 12:32:38
// )
// ……
// ……
fclose($f);

关于 CSV 是什么文件这里就不多做解释了,笔者毕业时的第一个项目中就有很多操作 CSV 文件的小功能,也可以说,这个 fgetcsv() 函数是笔者对于文件操作的启蒙函数。它可以方便地按行读取 CSV ,并将它们解析成数组格式方便我们地操作。不过一般如果是 Excel 文件转换过来的内容,我们都会将第一行标题行排除掉,当然,这个就是根据业务开发的实际情况来说啦。

读取过滤HTML

// fgetss
$f = fopen('./html_test.txt', 'r');
while (($c = fgetss($f)) !== false) {
    echo $c, PHP_EOL;
}
// PHP Deprecated:  Function fgetss() is deprecated
fclose($f);

fgetss() 函数在读取文件的时候可以过滤掉 HTML 代码,不过这个函数已经废弃了。

中文读取问题

对于中文的读取来说,我们最主要关心的就是中文字符和英文字符所占字节的区别问题,上面已经说过了,中文如果是 UTF8 编码格式,将占用 3 个字节,如果是 GBK 之类的将占用 2 个字节。所以如果我们使用 fread() 时,要使用对应编码的倍数来读取,比如下面我们的测试文件是 UTF8 编码的,需要按三个字符的方式读取,就需要传递参数为 6 。

// 中文测试
$f = fopen('./cn_test.txt', 'r+');

while (!feof($f)) {
    $contents = fread($f, 6);
    echo $contents, PHP_EOL;
}
// 我本
// 无为
// 野客
// ,飘
// 飘浪
// 迹人
// 间。

// 一?
// ?被?
// ……
// ……

while (!feof($f)) {
    $contents = fread($f, 1024);
    echo $contents, PHP_EOL;
}
//

rewind($f);
while (!feof($f)) {
    $contents = fread($f, 1024);
    echo $contents, PHP_EOL;
}
// 我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。
// 流霞细酌咏诗篇。且与白云为伴。

rewind($f);
while (($c = fgetc($f)) !== false) {
    echo $c, PHP_EOL;
}
// ?
// ?
// ?
// ……
// ……

rewind($f);
while (($c = fgets($f)) !== false) {
    echo $c, PHP_EOL;
}
// 我本无为野客,飘飘浪迹人间。

// 一时被命住名山。未免随机应变。

// 识破尘劳扰扰,何如乐取清闲。

// 流霞细酌咏诗篇。且与白云为伴。

fclose($f);

fread() 函数读取的内容中间为什么还会出现乱码呢?因为我们的换行符还是按英文码只占一个字节的呀!另外,fgetc() 函数就比较惨了,fgets() 函数还是能够正常地读取地。

读取剩余内容

$f = fopen('./cn_test.txt', 'r+');

echo fgets($f), PHP_EOL;
// 我本无为野客,飘飘浪迹人间。

echo fpassthru($f), PHP_EOL;
// 一时被命住名山。未免随机应变。
// 识破尘劳扰扰,何如乐取清闲。
// 流霞细酌咏诗篇。且与白云为伴。

rewind($f);

在这段测试代码中,我们使用 fgets() 读取了一行内容,然后再使用 fpassthru() 直接就将文件中剩余的内容全部读取出来了。这就是 fpassthru() 函数的作用,它可以将文件中游标之后全部剩余的内容读取出来。

fseek($f, 3 * 14 + 1);
echo fgets($f), PHP_EOL;
// 一时被命住名山。未免随机应变。

另外还有一个 fseek() 函数,可以指定当前从哪个位置开始读取,可以将它也看做是游标操作的一部分。

rewind($f);
fseek($f, 14 * 2 * 3 + 1);
echo ftell($f), PHP_EOL; // 85

ftell() 函数则是返回的文件剩余的字节信息。

文件句柄信息

print_r(fstat($f));
// Array
// (
//     [0] => 16777220
//     [1] => 8708492112
//     [2] => 33188
//     [3] => 1
//     [4] => 501
//     [5] => 20
//     [6] => 0
//     [7] => 177
//     [8] => 1603414680
//     [9] => 1603414679
//     [10] => 1603414679
//     [11] => 4096
//     [12] => 8
//     [dev] => 16777220
//     [ino] => 8708492112
//     [mode] => 33188
//     [nlink] => 1
//     [uid] => 501
//     [gid] => 20
//     [rdev] => 0
//     [size] => 177
//     [atime] => 1603414680
//     [mtime] => 1603414679
//     [ctime] => 1603414679
//     [blksize] => 4096
//     [blocks] => 8
// )

fstat() 函数和之前文章中我们讲过的 stat() 函数的功能是一样的,只不过它需要的是一个句柄参数,然后返回这个句柄对应文件的信息。而 stat() 直接给的是文件的路径。

文件截断

// 文件会变
ftruncate($f, 14*2*3+4);
echo fread($f, 8094), PHP_EOL;
// 我本无为野客,飘飘浪迹人间。
// 一时被命住名山。未免随机应变。
fclose($f);

ftruncate() 函数会从指定的位置截断文件内容。在这里我们只保留了前两行的内容,后面的内容就被截断掉了。使用这个函数需要注意的是,它会改变原有文件的内容。

读取文件并从格式化输入

$f = fopen("users_test.txt", "r");
while ($userinfo = fscanf($f, "%s\t%s\t%s\n")) {
    print_r($userinfo);
}
// Array
// (
//     [0] => javier
//     [1] => argonaut
//     [2] => pe
// )
// Array
// (
//     [0] => hiroshi
//     [1] => sculptor
//     [2] => jp
// )
// Array
// (
//     [0] => robert
//     [1] => slacker
//     [2] => us
// )
// Array
// (
//     [0] => luigi
//     [1] => florist
//     [2] => it
// )
fclose($f);

fscanf() 函数会根据第二个参数传递的内容来格式化文件的内容。就像会用 printf() 函数一样,只不过它是从读取的角度来获得数据内容。这里会将制表符作为分隔来形成格式化的结果数组。

文件内容匹配

var_dump(fnmatch('*fall[ing]*', file_get_contents('./test.txt'))); // bool(true)

fnmatch() 函数用于判断给定的内容中是否包含第一个参数中指定的规则。它有点像正则表达式相关的函数的用法,而且并不是操作文件的,是针对字符串的。不过它的规则定义是以 Linux 系统中的文件操作匹配规则为准的,也就是说它不是完全的正则规则。就像我们经常在 Linux 中查看某个文件的信息:ll *.txt 这样。

进程文件读取操作

这个是什么意思呢?其实就是我们可以执行一段操作系统的进程代码,然后获得它的结果,这个流会以文件流的形式返回给 PHP 形成一个文件流句柄。

$handle = popen("/bin/ls", "r");
while(!feof($handle)){
    echo fgets($handle);
}
pclose($handle);
// 1.PHP中的日期相关函数(三).php
// 2.学习PHP中的目录操作.php
// 3.学习PHP中的高精度计时器HRTime扩展.php
// 4.PHP中DirectIO直操作文件扩展的使用.php
// 5.学习PHP中Fileinfo扩展的使用.php
// 6.PHP中的文件系统函数(一).php
// 7.PHP中的文件系统函数(二).php
// 8.PHP中的文件系统函数(三).php
// cn_test.txt
// csv_test.csv
// html_test.txt
// test.txt
// timg.jpeg
// users_test.txt
// write.txt

文件写入

文件写入就比较简单了,就这么一点代码的介绍。而且也就三个函数。

// 写入
$f = fopen('write.txt', 'w');
fwrite($f, "This is Test!\n");
fputs($f, "This is Test2!!\n");
$csv = [['id', 'name'],[1, 'Zyblog'], [2, '硬核项目经理']];
foreach($csv as $v){
    fputcsv($f, $v);
}
fclose($f);
// This is Test!
// This is Test2!!
// id,name
// 1,Zyblog
// 2,硬核项目经理

fwrite() 用于向文件句柄中写入内容。fputs() 是 fwrite() 的别名,它们两个是一个东西。fputcsv() 函数则是以 CSV 的格式将数组内容写入到文件中,它还有其它的参数可以修改分隔符具体使用哪个符号,在这里我们默认就是逗号。

文件加锁

$fp = fopen("/tmp/lock.txt", "w+");

if (flock($fp, LOCK_EX)) { // 进行排它型锁定
    fwrite($fp, "写入数据:" . date('H:i:s') . "\n");
    if(!$argv[1]){
        sleep(50);
    }
    fflush($fp); // 释放锁之前刷新缓冲区
    flock($fp, LOCK_UN); // 释放锁定
} else {
    echo "无法获得锁,不能写入!";
}

fclose($fp);

锁定一个文件,然后其它的操作就不能读取它了,这种操作一般在多线程或者多个功能会同时操作一个文件时会非常常用。flock() 的第二个参数可以设置读锁、写锁等,这里我们使用的是 LOCK_EX 共享排它锁,也就是一个写锁。当我们运行这段代码后,在停留的时间内容,其它的脚本是无法写入数据的,如果有同时操作这个文件的脚本在运行也会卡在这里直到这边的锁释放掉。

  • LOCK_SH 取得共享锁定(读取的程序)。
  • LOCK_EX 取得独占锁定(写入的程序。
  • LOCK_UN 释放锁定(无论共享或独占)。
  • 如果不希望 flock() 在锁定时堵塞,则是 LOCK_NB(Windows 上还不支持)。

fflush() 用于刷新缓冲区,这个也是之前讲过的关于 PHP 中缓冲区相关的知识,大家可以回去温习一下,PHP中的输出缓冲控制。在文件操作中,使用这个函数就能马上刷新缓冲区的内容并将内容写入到具体的文件中。

总结

是不是很嗨,一下子学习了这么多函数。这篇文章结束也就是 PHP 原生的这些文件操作函数就学习完了。当然,了解只是一方面,更多的还是要多多尝试应用到自己的项目中。

测试代码:

https://github.com/zhangyue0503/dev-blog/blob/master/php/202010/source/8.PHP中的文件系统函数(三).php

参考文档:

https://www.php.net/manual/zh/ref.filesystem.php

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: