PHP中的文件和目录

时间:2022-09-30 16:35:42

PHP中的文件和目录

这是咱们前面讲过动态网页的结构,那么我们根据这个图回忆一下前面学的东西。

咱们前面学了php的变量、运算符和流程控制,是不是相当于我们学会了做“运算器”

咱们学的表单、http的请求以及 G E T / _POST等是不是相当于学会了“输入设备”

咱们捋一下流程:
通过http请求(含数据), P O S T / _GET接收数据,然后php运算处理,返回给浏览器

graph LR
http请求-->$_POST/$_GET接收数据
$_POST/$_GET接收数据-->PHP运算处理
PHP运算处理-->返回到浏览器输出

其实我们是不是已经完整的学完了一种动态网页访问流程。不过咱们这个流程似乎比着上面的流程还有点去区别,就是少了存储器。

其实存储器是存在的,比如我们前面写的例子:

<?php

$id = $_GET['id'];

//方法1

/*$content = '';
if ($id == 1) {
    $content = '文章1的内容';
}elseif ($id == 2) {
    $content = '文章2的内容';
}elseif ($id == 3) {
    $content = '文章3的内容';
}elseif ($id == 4) {
    $content = '文章4的内容';
}elseif ($id == 5) {
    $content = '文章1的内容';
}else{
    $content = '错误,没有这个文章';
}
echo $content;*/

//方法2

$articles = array('文章1的内容','文章2的内容','文章3的内容','文章4的内容','文章5的内容');
$num = $id - 1;
if(in_array($num, array(0,1,2,3,4,5))){
    echo $articles[$num];
}else{
    echo '错误,没有这个文章';
}

第一种方法,我们把内容写在了php运算过程中了,和运算混写在一起了;第二种方法中,我们把数据保存在一个数据里,然后根据传来的参数去数据里调配内容。

这两种写法,都是把php的运算处理和数据的保存放到一起,第二种方法虽然似乎分离开来写,但是最终的保存还是在同一个文件里。

这样是不是说明,咱们动态网页的访问流程中有内容存储的过程?这样我们前面的那个流程图的所有部分是不是都涉及到了?

这样写虽然能达到保存数据的目的,但是他的缺点也是十分明显的,比如:如果在其它的文件里我们也需要调去一篇文章的内容,就必须要再写一遍文章的内容保存到新建的这个php文件中,如果将来这篇文章内容有修改,那么是不是要把涉及这篇文章的所有文件都要修改一遍?这样是不是非常麻烦,非常的不易维护?这个问题怎么解决?

其实,通过前面我们的两个方法的对比,我们就能看出思想:分离。方法2中,我们把功能不同的部分分开,php运算的部分写一块,内容保存的部分写在另外一块。那么我们完全可以把保存也分离开来,比如我们把文章的内容保存在一个文件中,所有需要运算的代码都去这个文件读取内容,然后需要更改的时候,只需要修改一下这个文件里的内容就行了。

那么接下来,我们就学习一下php对文件的操作:

前面我们说了:

我们把文章的内容保存在一个文件中,所有需要运算的代码都去这个文件读取内容,然后需要更改的时候,只需要修改一下这个文件里的内容就行了

这段话是不是说明我们对文件的操作有三种情况:“读”、“写”、“修改”,其实修改也就是“读”和“写”一种连续操作,那么我们其实对文件的操作就剩两种情况:“读”和“写”

读文件

我们平时读取一个文件的一个流程是什么?

graph LR
找到文件-->打开文件
打开文件-->读取内容
读取内容-->关闭文件

php的读取文件也是按照这个流程的,每一步操作都有自己内置的函数:

获取文件长度:filesize

打开文件:fopen

读取文件:fread

关闭文件:fclose

$f = fopen('./file', 'r');

print_r($f);

我们先打开一下文件,不要在意文件的后缀名,看看返回值是什么!

我们可以看到,返回值是Resource,这是一个资源类型,我们前面学变量的类型的时候,讲过有哪8大类型?

什么是资源类型? PHP手册(语言参考部分)中这样定义的:资源 resource 是一种特殊变量,保存了到外部资源的一个引用。简单的来说,我们可以把它理解成一个通道,通过这个通道,我们可以对外部资源进行操作,就像我们喝牛奶时用的吸管一样,我们可以通过这个吸管吸出牛奶,也可以通过这个习惯从外部往牛奶盒里灌装牛奶。

同样的,我们通过前面打开的资源可以读数据,就像通过吸管吸出牛奶一样。

$f = fopen('./file', 'r');
$res = fread($f, 3);

print_r($res);
fclose($f);
echo gettype($res);

如果我们想全部读取出来,怎么操作?这就用到了我们的filesize函数了。

$f = fopen('./file', 'r');
$res = fread($f, filesize('./file'));

print_r($res);
fclose($f);
echo gettype($res);

我们可以看到文件的内容被读出来了,如果我们保存每篇文章内容的时候用特殊的符号做个分割标记,我们拿着读取到的数据,用我们前面学的把字符串分割成数组的函数分割成数组,然后再根据接收来的参数,做出不同的返回值就行了。

分隔符的选择:尽量避免可能和文章的内容相同就行,比如我们可以用“{!:delimiter:!}”作为分隔符。

比如咱们文章的内容是这样的:

文章11的内容{!:delimiter:!}文章22的内容{!:delimiter:!}文章33的内容{!:delimiter:!}文章44的内容{!:delimiter:!}文章55的内容

$f = fopen('./file', 'r');
$res = fread($f, filesize('./file'));
fclose($f);
$articles = explode('{!:delimiter:!}', $res);

print_r($articles);

通过打印结果,我们是不是可以看到,前面的那个文章列表的代码可以这样改写了。

$f = fopen('./file', 'r');
$res = fread($f, filesize('./file'));
fclose($f);
$articles = explode('{!:delimiter:!}', $res);

$num = $id - 1;
if(in_array($num, array(0,1,2,3,4,5))){
    echo $articles[$num];
}else{
    echo '错误,没有这个文章';
}
写文件

前面我们学了读文件,接下来我们学习写文件,还是老路子,我们平时写文件的流程是什么?

先看看写入文件流程:

graph LR
找到文件-->打开文件
打开文件-->写入内容
写入内容-->关闭文件

修改文件内容流程:

graph LR
找到文件-->打开文件
打开文件-->读取内容
读取内容-->找到修改的部分
找到修改的部分-->修改内容
修改内容-->写入新内容
写入新内容-->关闭文件

从流程中可以看到,咱们流程比着前面的“读文件流程”只多个“写入内容”,写入文件PHP用的是fwrite。下面我们写一遍:

添加文件内容:

//开头写入模式打开
/*$f = fopen('./file', 'w');
$content = '我是中国人!';
fwrite($f, $content);
fclose($f);*/

//追加写入模式打开
$f = fopen('./file', 'a');
$content = '我爱中国!';
fwrite($f, $content);
fclose($f);

接下来我们看看修改文件内容:

//读写模式打开文件
$f = fopen('./file', 'r+');
//读取文件的所有内容
$result = fread($f, filesize('./file'));
//对文件内容进行修改
$result_array = explode('{!:delimiter:!}', $result);
$change = '我是修改文章33后的内容';
$result_array[2] = $change;
$result_string = implode('{!:delimiter:!}', $result_array);
//将新内容写入文件
fwrite($f, $result_string);
fclose($f);

运行该段程序后,我们会发现,并不是我们想要的结果,它直接在文件的后面追加内容了,可是我们明明用“r+”打开的文件啊,“r+”模式打开,文件的指针不是在开头吗?想一想为什么。

其实原因也很简单,因为我们使用fread的时候,把文件的指针移动到了内容的末尾,因此,这个时候我们写入,就是从内容的末尾开始写入的。因此,如果想覆盖写入,只需要将文件指针移到开头就行了,移动文件指针到开头的函数是:rewind();那么为omen的代码这样修改一下就行了:

//读写模式打开文件
$f = fopen('./file', 'r+');
//读取文件的所有内容
$result = fread($f, filesize('./file'));
//对文件内容进行修改
$result_array = explode('{!:delimiter:!}', $result);
$change = '我是修改文章33后的内容';
$result_array[2] = $change;
$result_string = implode('{!:delimiter:!}', $result_array);
//移动文件指针到开头
rewind($f);
//将新内容写入文件
fwrite($f, $result_string);
fclose($f);

其实,我们会发现,我们不管读还是写,流程基本是一样,每次都要写这些代码,根据我们前面学的函数思想,我们完全可以把读和写内容分别封装成函数,每次读的时候,传点参数就行了。

不过php关于文件的读写,已经给我们封装过两个函数:

file_put_contents 和 file_get_contents

下面我带着大家简单的学一下这两个的简单用法,具体的其它用法需要大家课下好好的看手册和查资料。

file_put_contents( f i l e n a m e , data[, f l a g , context])

和依次调用fopen(),fwrite() 以及 fclose() 功能一样,我们这里就学习一下他的写入文件

$data = 'DDDDDDDDDDDDDDDDDDDD';
print_r(file_put_contents('./putcontent', $data));

默认情况下,如果被写入的文件存在,那么是覆盖写入内容,如果想追加写入,可以置顶第三个参数为:FILE_APPEND 即可。

$data = 'EEEEEEEEEEEEEEEE';
print_r(file_put_contents('./putcontent', $data, FILE_APPEND));

$data 也可以为数组

$data = array('aaaaaaaaaa', 'CCCCCCCCC', 'bbbbbbbbbb');
print_r(file_put_contents('./putcontent', $data));

file_get_contents($path)

print_r(file_get_contents('./putcontent'));