8.2 常见的文件操作
文件操作是程序开发中最基本的内容之一。实际应用中,经常需要从文件取数据,或者向文件写入数据,如分析日志数据和记录日志等。因此,作为编程的基本功之一,读者需要努力掌握文件处理的有关内容,并在实际应用中加强实践。本节将为读者介绍一些基本的文件操作函数。
8.2.1 打开和关闭文件
在程序中,处理文件的一般流程如图8-5所示。
图8-5 用程序操作文件的一般流程
要通过PHP读出文件内容,或者向文件写入数据,首先要做的是打开文件。在PHP中可以使用函数fopen()打开一个文件,该函数的语法如下。
$fp = fopen(string $filename,string $mode);
该函数可以打开本地或远程文件,参数$filename是指要打开的文件的文件名,返回值是文件处理句柄$fp,程序通过$fp来操作文件。如果打开失败,函数返回FALSE。该函数的第2个参数$mode是字符串类型,指打开文件的模式。打开文件时,之所以要指定模式,是为了告诉操作系统如何处理即将打开的文件。例如,如果需要向某文件写入一些数据,可以向该函数的第2个参数传参数w,此时,这个参数表示的含义是以写入方式打开文件。表8-1列举了常用的文件打开模式。
表8-1 函数fopen()中参数$mode的主要取值
如下示例代码即通过函数fopen()打开文件。
$fp = fopen($_SERVER['DOCUMENT_ROOT']."/../files/read.txt",'w');
上述代码通过函数fopen()打开files目录下的read.txt文件,这里使用了PHP的预定义变量$_SERVER[‘DOCUMENT_ROOT’],其后跟着的..表示服务器文档根目录的上级目录。这段代码要打开的文件在服务器文档目录之外,是出于安全上的考虑。传入该函数的第2个参数w,表示以写入方式打开文件read.txt。
注意 在Linux/UNIX系统中指定文件路径时,使用斜杠(/)。如果是在Windows环境下,指定目录时,可以使用斜杠(/)或者反斜杠(\)。如果使用的是\,在使用函数fopen打开指定目录的文件时,需要对\转义,即使用\\来指定目录。
例如,在Windows平台打开C盘某目录下的文件,使用\指定目录,其代码如下。
$fp = fopen("C:\\data\\log.dat");
一般实际开发中很少使用\来指定目录,因为这样的代码只能运行于Windows环境下,不利于程序的移植。除了打开本机文件,函数fopen()还可以通过HTTP协议、FTP协议或其他网络协议打开远程文件。打开文件后,就可以向文件写入数据,或者从文件中读取数据。
当完成数据的写入或读取后,文件操作的最后一步需要关闭文件,PHP程序中使用函数fclose()关闭一个已经打开的文件。如果文件成功关闭,该函数返回TRUE,否则返回FALSE。下面的代码片段演示了使用函数fcolse()关闭打开的文件。这行代码中的变量$fp就是已经打开的文件的处理句柄。
fcolse($fp);
8.2.2 读出文件的内容
文件打开后,就可以从其中读出内容,以供程序使用。本节通过一个具体实例介绍PHP中和读文件有关的函数。
(1)建立一个文本文件,供程序打开和读其内容之用。该文本内容如下。
<b><h3> 最新动态</h3></b> 40 名企业家自费植树 中国战机南疆出击 姚明31 分火箭胜太阳
(2)将该文件以名称info.dat保存在服务器文档根目录的上级目录data下。然后编写读取这个文件内容的PHP程序,该程序如代码8-4所示。
代码8-4 读取文件内容8-4.php
01 <?php 02 $fp = fopen($_SERVER['DOCUMENT_ROOT']."/../data/info.dat",'r');// 打开指定的文件 03 04 if(!$fp) 05 { 06 echo "<b>Error: 打开文件错误,请检查目录是否正确,或稍后再试!</b>"; 07 exit; 08 } 09 10 while(!feof($fp)) // 循环读取文件 11 { 12 $line = fgets($fp); // 读取文件的一行 13 echo $line; 14 echo '<br/>'; 15 } 16 17 fclose($fp); // 关闭文件 18 ?>
【代码解析】代码第02行使用函数fopen()打开文件,并且向其传入了第2个参数r,表示以只读方式打开该文件,此时程序只可以读出文件的内容而不能向文件写入数据。接着,程序判断文件是否成功打开,即判断句柄$fp是否为TRUE。如果打开文件失败,程序会向页面输出一个错误信息,然后立即终止程序执行,语句“exit;”用来终止程序继续执行。
图8-6 读取文件内容
程序第10行使用了while循环来读文件,直到文件的末尾,其中,函数feof()用来判断是否到了文件的末尾。该函数使用文件句柄$fp作为其参数,当达到文件末尾时,它会返回TRUE。这个程序中,当没有达到文件末尾时,函数执行while语句的循环体。第12行语句的意思是取出文件中的一行赋给变量$line,函数fgets()会读取文件中的一行,直到遇到换行字符(\n)。该函数接受的参数是已打开的文件的句柄,返回值是文件的一行内容。函数fgets()可以接受第2个参数,表示读取一行内容的字节数(bytes),例如fgets($fp,100)表示读取一行中的100字节的内容,如果没有传入该参数,fgets()默认读取1024个字节内容。最后,第17行使用函数fclose($fp)关闭已打开的文件。代码8-4的执行结果如图8-6所示。
除了使用函数fgets()读出文件的一行内容外,还可以使用另外3个函数读入整个文件,即函数readfile()、函数file()和函数get_file_contents()。
函数readfile()读入文件的整个内容,该函数的语法如下。
int readfile(string $filename);
该函数的参数$filename是要打开的文件名称,如果打开文件成功,函数的返回值是从文件读入的字节数,否则返回FALSE。该函数还有两个可选参数,它们是比较高级的用法,这里不再赘述。
函数file()可以将整个文件读入一个数组,该函数的语法如下。
array file(string $filename, [int use_include_path]);
函数file()的参数$filename是要打开的文件,第2个参数是可选的,如果其值为1,表示PHP将在include_path中查找该文件,include_path是php.ini文件中的一个配置项。该函数读入整个文件的内容,将其存入数组后返回该数组。数组中的每个单元对应文件中的每一行,包括换行符在内。如果file()处理失败,返回值是FALSE。
函数get_file_contents()和函数file()类似,只不过它将整个文件内容读入一个字符串。该函数的语法如下。
string get_file_contents(string $filename);
该函数返回文件$filename的所有内容,如果失败,返回值是FALSE。
8.2.3 向文件写入内容
除了从文件读出内容,有时还需要向文件写入数据。本小节将介绍如何在PHP程序中向文件写入数据。通过3个函数可以完成对文件的写入操作,即函数fwrite()、函数fputs()和函数file_put_contents()。
函数fwrite()的语法如下。
int fwrite($fp, string $content [, int $length));
参数$fp是已打开的文件的句柄,$content是要向文件写入的内容。第3个参数$length是一个可选参数,表示写入数据的最大的字节数,这就是说,当向文件写入了length个字节后,写入就会停止。当然,如果$content的长度小于$length,函数写完$content后就已停止写入。如果写入成功,该函数返回写入的字符数,否则返回FALSE。代码8-5演示了函数fwrite()的用法。
代码8-5 使用函数fwrite()向文件写入数据8-5.php
01 <?php 02 $file = "data.txt"; 03 $content = " 内容标题\r\n 内容第一行\r\n 内容第二行"; // 要写入文件的内容 04 05 // 打开文件$file 时,使用追加模式,此时文件指针会在文件开始处 06 if(!$fp = fopen($file,'a')) 07 { 08 echo " 打开文件$file 失败!"; 09 exit; 10 } 11 12 if(fwrite($fp,$content) === FALSE) // 将内容$content 写入文件 13 { 14 echo " 写入文件失败!"; 15 exit; 16 } 17 18 echo " 写入文件成功!"; 19 fclose($fp); // 关闭文件 20 ?>
【代码解析】这段程序向当前目录下的文件data.txt中写入一些内容,因为使用了a模式打开文件,如果当前目录下不存在data.txt,函数fopen()会尝试创建该文件。代码第12行通过函数fwrite()将变量$content所存内容写入data.txt,同时判断是否写入成功,如果写入失败,则向页面输出一个错误提示信息。
注意 因为是在Windows平台下向文件写入内容,所以变量$content里的数据使用\r\n作为一行的结束符号,即换行。而在UNIX系统中,使用\n作为行结束字符。
图8-7 通过fwrite()向文件写入的内容
通过浏览器执行该程序,如果执行正常,会出现“文件写入成功!”的提示,同时到当前目录中打开文件data.txt,可以看到文件里已经写入内容,如图8-7所示。
函数fputs()是函数fwrite()的别名,其实它就是函数fwrite(),用法和fwrite()一样,这里不再赘述。
函数file_put_contents()也可以完成向文件写入数据,该函数的语法如下。
int file_put_contents(string $filename, string $data);
该函数主要有两个参数,参数$filename是要写入数据的文件的名称,参数$data是要写入的数据。使用函数file_put_contents(),相当于依次调用了fopen()、fwrite()和fclose(),因此,程序中不必再使用这3个函数。如果执行成功,该函数返回写入文件的字节数,否则返回FALSE。
8.2.4 获取文件的相关信息
文件的相关信息主要涉及文件的所有者、文件的大小和文件的类型等,PHP可以通过以下函数获取文件的这些主要信息。
·函数fileowner(),取得文件的所有者,返回文件所有者的用户ID,如果失败,返回FALSE。
·函数filesize(),取得文件的大小,返回值是文件大小的字节数,如果失败,返回FALSE。
·函数filetype(),返回文件类型,可能的值有file(文件)、dir(目录)、link(符号链接)、block(块)、unknown(未知)等。如果失败,返回FALSE。
代码8-6演示了这些函数的用法。
代码8-6 获取文件的主要信息8-8.php
01 <?php 02 echo " 文件的所有者(用户ID ):"; 03 echo fileowner("data.txt"); // 取得文件的所有者 04 echo "<br>"; 05 echo "<br>"; 06 07 echo " 文件的大小:"; 08 echo filesize("data.txt"); // 取得文件的大小 09 echo "<br>"; 10 echo "<br>"; 11 12 13 echo " 文件的类型:"; 14 echo filetype("data.txt"); // 取得文件的类型 15 echo "<br>"; 16 ?>
【代码解析】这段代码向页面输出当前目录下文件data.txt的一些主要信息,如文件所有者、文件大小和文件类型,执行结果如图8-8所示。
8.2.5 一些判断文件性质的函数
PHP中判断文件性质的函数主要有以下几个。
·函数is_dir($filename),判断由参数$filename指定的文件是否是目录。如果文件名存在并且是一个目录,该函数返回TRUE,否则返回FALSE。
·函数is_file($filename),判断由参数$filename指定的文件是否是普通文件。如果文件名存在并且是一个普通文件,该函数返回TRUE,否则返回FALSE。
·函数is_readable($filename),判断由参数$filename指定的文件是否可读。文件可读时,该函数返回TURE,否则返回FALSE。
·函数is_writeable($filename),判断由参数$filename指定的文件是否可写。文件可写时,该函数返回TRUE,否则返回FALSE。函数is_writeable()经常在向一个文件写入内容之前调用,如果该文件可写,才向文件里写入数据。
代码8-7演示了这些函数的用法。
代码8-7 判断文件的性质8-7.php
01 <?php 02 $file = "data.txt"; // 文件名称 03 04 if(is_dir($file)) // 判断该文件是否是目录 05 { 06 echo " 文件 $file 是个目录"; 07 echo "<br/>"; 08 } 09 else 10 { 11 echo " 文件 $file 不是目录"; 12 echo "<br/>"; 13 } 14 15 if(is_file($file)) // 判断该文件是否是普通文件 16 { 17 echo " 文件 $file 是一个普通文件"; 18 echo "<br/>"; 19 } 20 21 if(is_readable($file)) // 判断该文件是否可读 22 { 23 echo " 文件 $file 是可读的"; 24 echo "<br/>"; 25 } 26 else 27 { 28 echo " 文件 $file 是不可读的"; 29 echo "<br/>"; 30 } 31 32 if(is_writeable($file)) // 判断该文件是否可写 33 { 34 echo " 文件 $file 是可写的"; 35 echo "<br/>"; 36 } 37 else 38 { 39 echo " 文件 $file 是不可写的"; 40 echo "<br/>"; 41 } 42 ?>
【代码解析】这段代码判断了当前目录下文件data.txt的一些性质,包括它是否是目录、是不是文件、是可读还是可写,执行结果如图8-9所示。
图8-8 使用PHP的函数获取文件的主要信息
图8-9 使用PHP的函数判断文件的性质
注意 这段代码中输出使用了双引号字符串,其中变量$file后紧跟着中文字符,这时需要在变量$file后加入空格,程序才会有正确的输出。否则PHP会认为变量$file后的中文字符也是变量名的一部分,从而导致输出有问题。