第5 章 PHP 中的文件处理技术
文件处理技术是一种编程语言的基本处理能力之一。本章将介绍PHP 中的各种文件处理
技术和技巧。虽然很多数据都是保存在数据库中,但是文件管理依然占据着重要的地位。
文件处理一般包含以下一些步骤。
(1)打开文件。打开指定的文件,如果该文件不存在,则创建该文件。
(2)文件操作。在打开文件之后,就可以对该文件进行各种操作。如果文件中已经包含
数据,则可以从中读取数据,重新向文件写入数据,或者向文件中添加数据。
(3)关闭文件。在完成处理文件之后,需要关闭该文件。
PHP 中提供了许多与文件相关的函数,可以用来将网页上的数据保存到文件,将文件中的数
据检索到网页,或者仅仅修改已有的文件数据,或者添加新数据。其中最常用的文件操作如下:
(1)检查文件是否存在;
(2)打开文件;
(3)读取文件;
(4)向文件中写入数据。
下面详细介绍以上的操作。
5.1 检测文件或者目录是否存在
在PHP 中,可以通过函数file_exists 来检测一个文件或者目录是否存在。该函数声明
如下:
bool file_exists ( string filename)
如果由filename 指定的文件或目录存在则返回TRUE,否则返回FALSE。
提示
在Windows 中要用//computername/share/filename 或者\\computername\share\filename
来检查网络中的共享文件。
实例 5-1 检测文件是否存在
本实例使用file_exists 函数检测文件是否存在,如代码5-1 所示。
【代码 5-1】 file_exists.php
<?php
$filename = 'hello.txt';
$catalog="hello";
//文件检测
第5 章 PHP 中的文件处理技术 161

if (file_exists($filename)) {
 print $filename."文件存在!<br>";
 } else {
 print $filename."文件不存在!<br>";
 }
 //目录检测
 if (file_exists($catalog)) {
 print $catalog."目录存在!";
 } else {
 print $catalog."目录不存在!";
 }
 ?>


file_exists.php 文件的执行结果如图5-1 所示。
图 5-1 file_exists.php 文件的执行结果
由于笔者已在当前目录下创建了目录“hello”,所以执行结果显示该目录存在,而当前目
录下没有“hello.txt”文件,因此提示文件不存在。

5.2 打 开 文 件
任何对文件的操作都必须先要打开该文件。
在 PHP 中,打开一个文件使用的函数是fopen。
fopen 函数的声明如下所示:
int fopen ( string filename, string mode [, int use_include_path [, resource
zcontext]])
调用fopen 函数的时候,需要传递2 个、3 个或者4 个参数。通常使用两个参数。其中
第一个参数filename 表示要打开的文件名,而第二个参数mode 表示打开的方式。不同的打
开方式,可以进行的操作是不一样的。
fopen()将filename 指定的名字资源绑定到一个流上。如果filename 是“scheme://...”的
格式,则被当成一个URL,PHP 将搜索协议处理器(也被称为封装协议)来处理此模式。如
果该协议尚未注册封装协议,PHP 将发出一条消息来帮助检查脚本中潜在的问题并将
filename 当成一个普通的文件名继续执行下去。
如果 PHP 认为filename 指定的是一个本地文件,将尝试在该文件上打开一个流。该文件
必须是PHP 可以访问的,因此需要确认文件访问权限是否允许该访问。如果激活了安全模式
或者open_basedir 则会应用进一步的限制。
如果 PHP 认为filename 指定的是一个已注册的协议,而该协议被注册为一个网络URL,
PHP 将检查并确认allow_url_fopen 已被激活。如果关闭了,PHP 将发出一个警告,而fopen
的调用则失败。
可以这样理解,如果参数 filename 以http://开头,则表示打开的是远程Web 服务器上的
文件,如果以ftp://开头,则表示要从远程FTP 服务器上获取文件,并需要与指定的服务器建
162 PHP 网络编程技术与实例
立 FTP 会话。如果前面没有任何前缀,一般情况下表示打开本地文件。
第 2 个参数mode 有多种取值,用来指示文件是读、写还是附加。mode 参数的具体取值
如表5-1 所示。
表 5-1 fopen 函数中mode 的可能值列表
mode 说 明
'r' 只读方式打开,将文件指针指向文件头
'r+' 读写方式打开,将文件指针指向文件头
'w' 写入方式打开,将文件指针指向文件头并将文件大小设为零。如果文件不存在则尝试创建
'w+' 读写方式打开,将文件指针指向文件头并将文件大小设为零。如果文件不存在则尝试创建
'a' 写入方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建
'a+' 读写方式打开,将文件指针指向文件末尾。如果文件不存在则尝试创建
'x'
创建并以写入方式打开,将文件指针指向文件头。如果文件已存在,则fopen()调用失败并返回FALSE,生成一
条E_WARNING 级别的错误信息。如果文件不存在则尝试创建。这和给底层的open(2)系统调用指定
O_EXCL|O_CREAT 标记是等价的。此选项仅能用于本地文件
'x+'
创建并以读写方式打开,将文件指针指向文件头。如果文件已存在,则fopen()调用失败并返回FALSE,并生成
一条E_WARNING 级别的错误信息。如果文件不存在则尝试创建。这和给底层的open(2)系统调用指定
O_EXCL|O_CREAT 标记是等价的。此选项仅能用于本地文件
'b'
二进制模式。用于与其他模式进行连接。如果文件系统能够区分二进制文件和文本文件,可能会使用它。Windows
系统可以区分;而Unix 系统则不区分。推荐一直使用这个选项,以便获取最大程度的可移植性。二进制模式是
默认的模式
't' 用于与其他模式的结合。这个模式只是Windows 系统下的一个选项。不是推荐选项,除非曾经在代码中使用了
b 选项
提示
如果指定的文件需要从远程的HTTP 服务器上获取,则只能以只读方式打
开。这样可以有效地防止他人篡改网页。类似地,如果需要从FTP 服务器上
获取指定的文件,则只能以写或者读的方式打开,但不能同时以写和读的方式
打开。
在一些情况下,可能会遇到方式 b,这种方式只适合一定的平台,如windows,它能区
分文本和二进制格式。这种方式在诸如UNIX 的平台上不起作用。
注意
不同的操作系统产品具有不同的行结束习惯。当写入一个文本文件并想插
入一个新行时,需要使用符合操作系统的行结束符号。基于UNIX 的系统使用
\n 作为行结束字符,基于Windows 的系统使用\r\n 作为行结束字符,基于
Macintosh 的系统使用\r 作为行结束字符。如果写入文件时使用了错误的行结
束符号,则其他应用程序打开这些文件时可能导致数据发生改变,不是原来写
入的数据。
fopen 的第3 个参数use_include_path 是可选的,在按照由该参数指定的路径下查找文件
时使用它。如果希望在php.ini 文件中设定的include_path 路径中进行查找,则只需要将该参
数设置为1。
常用的打开文件的方法如代码 5-2 所示。
【代码 5-2】

<?php
 //只读方式打开文本文件,该文件路径为相对当前PHP 文件的路径
 $handle = fopen ("/home/rasmus/file.txt", "r");
 第5 章 PHP 中的文件处理技术 163
 //只写方式打开二进制文件,该文件路径为相对当前PHP 文件的路径
 $handle = fopen ("/home/rasmus/file.gif", "wb");
 //打开远程WEB 服务器文件 
 //打开远程FTP 文件
 $handle = fopen ("ftp://user:password@example.com/somefile.txt", "w");
 //打开本地机器上的绝对路径的文件,该种方式适合Unix 系统和Windows 系统
 $handle = fopen ("c:/data/info.txt", "r");
 //打开本地机器上的绝对路径的文件,该种方式适Windows 系统,如果使用反斜线,必须使用转义符
 //即双反斜线
 $handle = fopen ("c:\\data\\info.txt", "r");
 ?>


如果用户以“w”或者“a”模式打开一个文件时,该文件不存在,则系统会自动创建该
文件。
实例 5-2 创建文件
本实例通过fopen 函数创建一个文件,如代码5-3 所示。
【代码 5-3】 createfile.php

<?php
 //在hello 目录下创建一个1.txt 文件,以只写模式创建
 $handle = fopen ("hello/1.txt", "w");
 //关闭文件,使用fclose 函数
 fclose($handle);
 echo "/hello/1.txt 文件创建成功!<br>";
 //在C 盘根目录下创建一个temp.txt 文件,以追加模式创建
 $handle=fopen("c:/temp.txt","a");
 //同样也要关闭文件
 fclose($handle);
 echo "c:/temp.txt 文件创建成功!";
 ?>


createfile.php 文件的执行结果如图5-2 所示。
图 5-2 createfile.php 文件的执行结果
执行代码 5-3 后,可以去C 盘根目录下查看刚才创建的temp.txt 文件,同时也可以在当
前目录的子目录“hello”下创建了1.txt 文件。注意,要确保“hello”目录已经创建。
以上代码中虽然创建了文件,但是整个文件是空的,因此接下来的步骤是向文件中添加数据。
5.3 写入或者追加数据
5.3.1 写入数据
在PHP 中,写文件的函数有好几个,最常用的函数为fwrite(),也可以使用fputs()函数,
该函数是fwrite()函数的别名函数(两者的用法一样)。
164 PHP 网络编程技术与实例
fwrite()函数的声明如下:
int fwrite ( resource handle, string string [, int length])
fwrite()把string 的内容写入文件指针handle 处。如果指定了length,当写入了length 个
字节或者写完了string 以后,写入就会停止。
fwrite()返回写入的字符数,出现错误时则返回FALSE。
注意
如果给出了 length 参数,则magic_quotes_runtime 配置选项将被忽略,而
string 中的斜线将不会被去掉。
实例 5-3 将数据写入文件
本实例以只写方式打开一个文件,然后向文件中写入一行文字,如代码5-4 所示。
【代码 5-4】 writedata.php

<?php
 $filename = 'hello/1.txt';
 $somecontent = "我先被写入的!\r\n";
 $somecontent1 = "我后被写入的!\r\n";
 // 首先要确定文件存在并且可写
 if (is_writable($filename)) {
 // 在这个例子里,将使用只写模式打开$filename
 // 文件指针将会在文件的开头,如果原来文件中有其他数据,则会被删除
 if (!$handle = fopen ($filename, "w")) {
 print "不能打开文件 $filename";
 exit;
 }
 // 将$somecontent 写入到打开的文件中
 if (!fwrite($handle, $somecontent)) {
 print "不能写入到文件 $filename";
 exit;
 }
 print "成功地将\" $somecontent \"写入到文件$filename<br>";
 fclose($handle);
 $handle = fopen ($filename, "w"); //再次打开
 //继续打开文件写入另外一个字符串,原来写入的数据则被清除
 fwrite($handle, $somecontent1);
 fclose($handle);
 print "成功地将\" $somecontent1 \"写入到文件$filename";
 } else {
 print "文件 $filename 不可写";
 }
 ?>


writedata.php 文件的执行结果如图5-3 所示。
从图 5-3 中可以看出,虽然两句话都被写入到文件中,而实际上只有最后一句话被写入
到文件了,如图5-4 所示。
这是因为采用了只写模式打开,每次写入新数据的时候,原始数据都会被删除。
第5 章 PHP 中的文件处理技术 165
图 5-3 writedata.php 的执行结果图 5-4 最终被写入的数据
实例 5-4 写入多行数据
本实例实现一次将多行数据写入文件,如代码5-5 所示。
【代码 5-5】 writedata1.php

<?php
 $filename = 'hello/2.txt';
 $handle = fopen ($filename, "w");
 fwrite($handle, "1\r\n");
 fwrite($handle, "2\r\n");
 fwrite($handle, "3\r\n");
 fwrite($handle, "4\r\n");
 fwrite($handle, "5\r\n");
 fwrite($handle, "6\r\n");
 fwrite($handle, "7\r\n");
 fwrite($handle, "8\r\n");
 fclose($handle);
 ?>


执行代码5-5 后,会创建2.txt 文件,2.txt 文件的内容如图5-5 所示。
图 5-5 写入多行文本
从图 5-5 中可以看出,打开一个文件后可以一次写入多行文本。
提示 \r\n 在Windows 中表示字符串结束并且换行。
5.3.2 追加数据
前面介绍了向文件中写入数据,但是每次重新打开文件后,都会删除原来的数据,这样
很不方便。比如要将一些个人的基本信息保存在一个文本文件中,但不是一次性写入,而是
需要经常打开文件追加,这个时候,就需要使用追加模式来写入数据。
实例 5-5 追加数据
本实例实现打开一个已有文件,然后追加数据,如代码5-6 所示。
166 PHP 网络编程技术与实例
【代码 5-6】 appenddata.php

<?php
 $filename = 'hello/student.txt';
 $student1 = "姓名:小狗 \t 年龄:5 \t 性别:男\r\n";
 $student2 = "姓名:小猫 \t 年龄:4 \t 性别:女\r\n";
 $student3 = "姓名:小猪 \t 年龄:3 \t 性别:男\r\n";
 // 在这个例子里,首先使用只写模式模式打开$filename
 if (!$handle = fopen ($filename, "w")) {
 print "不能打开文件 $filename";
 exit;
 }
 // 将$student1 写入到打开的文件中
 if (!fwrite($handle, $student1)) {
 print "不能写入到文件 $filename";
 exit;
 }
 //fwrite($handle, $student1);
 print "成功地将\" $student1 \"写入到文件 $filename<br>";
 fclose($handle);
 $handle = fopen ($filename, "a"); //接着以添加模式打开文件
 //继续添加其他信息
 fwrite($handle, $student2);
 print "成功地将\" $student2 \"写入到文件 $filename<br>";
 fwrite($handle, $student3);
 print "成功地将\" $student3 \"写入到文件 $filename<br>";
 fclose($handle);
 ?>


appenddata.php 文件的执行结果如图5-6 所示。
图 5-6 appenddata.php 文件的执行结果
打开刚才创建的 student.txt,可以看到如图5-7 所示结果。
图 5-7 添加数据成功
5.4 关 闭 文 件
任何文件在打开操作后都必须关闭,否则可能会引起错误。在前面的例题中,其实已经
使用了关闭文件函数,即fclose()函数。fclose()函数的声明如下:
第5 章 PHP 中的文件处理技术 167
bool fclose ( resource handle)
fclose 函数将handle 指向的文件关闭。如果成功则返回TRUE,失败则返回FALSE。
提示 文件指针必须有效,并且是通过 fopen()或fsockopen()成功打开的。
简单示例如代码 5-7 所示。
【代码 5-7】

<?php
 $handle = fopen('somefile.txt', 'r');
 fclose($handle);
 ?>


5.5 读 取 数 据
前面介绍了如何创建文件、打开文件以及向文件中写入数据以及追加数据,接下来将介
绍如何从文件中读取数据。
5.5.1 读取一行数据
打开文件后,如果要逐行读取文件内容,可以使用下面的函数。
(1)ftets 函数。该函数的声明如下:
string fgets(int handle [, int length])
其中handle 参数是被打开的要读取数据的句柄,而length 参数表示要读取的数据长度。
该函数的作用是从handle 指向的文件中读取一行并返回长度最多为length−1 字节的字符串。
遇到换行符(包括在返回值中)、EOF 或者已经读取了length−1 字节后停止。如果没有指定
length,则默认为1KB,或者说1024 字节。出错时返回FALSE。
实例 5-6 一次读入一行数据
本实例演示了fgets 函数的应用,如代码5-8 所示。
【代码 5-8】 fgets.php

<?php
 $handle = fopen ("hello/student.txt", "r");
 while (!feof ($handle)) {
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 }
 fclose ($handle);
 ?>


fgets.php 文件的执行结果如图5-8 所示。
图 5-8 fgets.php 的执行结果
168 PHP 网络编程技术与实例
实例中使用代码循环读取了前面创建的 student.txt 文件中的数据。
提示 feof 函数为判断是否到了文件最后的函数,在后面会有详细介绍。
(2)fgetss 函数。fgetss 函数是fgets 函数的一个变体。其功能同fgets 函数基本类似,只
是fgetss 函数会过滤掉被读取内容中的HTML 和PHP 标记。
fgetss 函数的声明如下:
string fgetss( resource handle, int length [, string allowable_tags])
fgetss 函数和fgets()相同,只除了fgetss 尝试从读取的文本中去掉任何HTML 和PHP 标
记。可以用可选的第三个参数指定哪些标记不被去掉。当读取其他人写的文件的时候,可以
设置过滤一些恶意代码。因为一些恶意的HTML 和PHP 代码,可以很容易控制服务器。
实例 5-7 读取数据并过滤HTML 和PHP 标记
本实例演示了fgetss 函数的应用,如代码5-9 所示。
【代码 5-9】 fgetss.php

<?php
 $filename = 'hello/3.txt';
 $handle = fopen ($filename, "w");
 fwrite($handle, "<b>i like dancing very much!</b>\r\n");
 fwrite($handle, "<br>i like singing very much!\r\n");
 fclose($handle);
 echo "fgets 函数的输出结果:<br>";
 $handle = fopen ("hello/3.txt", "r");
 while (!feof ($handle)) {
 $buffer = fgets($handle,1024); //fgets 函数,不过滤<b>、<br>等html 标记
 echo $buffer;
 }
 fclose ($handle);
 echo "<br><br>fgetss 函数的输出结果:<br>";
 $handle = fopen ("hello/3.txt", "r");
 while (!feof ($handle)) {
 $buffer = fgetss($handle,1024); //fgetss 函数,过滤<b>、<br>等html 标记
 echo $buffer;
 }
 fclose ($handle);
 ?>


fgetss.php 文件的执行结果如图5-9 所示。
图 5-9 fgetss.php 文件的执行结果
从图 5-9 中可以看出,由于fgets 函数没有过滤,因此,在显示的时候<b></b>将加粗显
第5 章 PHP 中的文件处理技术 169
示字体,而<br>标记将会换行。而用fgetss 函数则过滤了这几个html 标记,所以在浏览器中
的显示,没有将字体加粗,同时也没有换行。读者也可以右键单击浏览器,在弹出菜单中选
择【查看源文件】,可以看到两次输出的内容分别为:

//fgets 函数输出
 <b>i like dancing very much!</b>
 <br>i like singing very much!
 //fgetss 函数输出
 i like dancing very much!
 i like singing very much!


(3)fgetcsv()函数。fgetcsv 函数也是fgets 函数的一个变体。该函数从文件指针中读入一
行并解析CVS 字段,该函数的声明如下:
array fgetcsv ( int handle, int length [, string delimiter [, string enclosure]])
和fgets()类似,只除了fgetcsv()解析读入的行并找出CVS 格式的字段然后返回一个包含
这些字段的数组。可选的第三个参数delimiter 的默认值是逗号。可选参数enclosure 的默认值
是双引号。delimiter 和enclosure 都被限制为一个字符。如果多于一个字符,则只使用第一个
字符。length 必须大于CVS 文件中长度最大的行(以便于处理行结束字符)。fgetcsv()出错时
返回FALSE,包括碰到文件结束时。
提示
CVS 文件中的空行将返回为一个包含有单个null 字段的数组,而不会被当
成错误。
如果在文件中使用了分隔符号,如逗号、制表符等,可以使用fgetcsv 函数将文件中读入
的一行分成多行。比如在appenddata.php 中,向student.txt 文件中写入了“$student1 = "姓名:
小狗\t 年龄:5\t 性别:男\r\n"”的记录,如果现在想将姓名、年龄以及性别分成三行显示,此时
可以通过分隔符“\t”来将该行分解成3 个字段,并保存在一个数组中。
实例 5-8 使用fgetcsv 函数解析CVS 文件
本实例介绍fgetcsv 函数的应用,代码5-10 所示。
【代码 5-10】 fgetcsv.php

<?php
 $row = 1;
 $handle = fopen ("hello/student.txt","r");
 while ($data = fgetcsv ($handle, 1000, "\t")) {
 $num = count ($data); //统计数组大小
 print "<p> 在第 $row 行中有 $num 个字段: <br>\n";
 $row++;
 for ($c=0; $c < $num; $c++) {
 print $data[$c] . "<br>\n";
 }
 }
 fclose ($handle);
 ?>


fgetcsv.php 文件的执行结果如图5-10 所示。
从图 5-10 中可以看出,文件student.txt 中的每行文本,都通过分隔符“\t”分隔开,然
后分别输出。
170 PHP 网络编程技术与实例
图 5-10 fgetcsv.php 文件的执行结果
5.5.2 读取整个文件
前面介绍的3 个函数主要用于逐行读取文件中的数据,但是很多时候不需要逐行读取数
据,而是要一次读取整个文件的数据。PHP 中提供了4 个函数用于读取整个文件的数据。
(1)readfile()函数。readfile 函数的声明如下:
int readfile ( string filename [, bool use_include_path [, resource context]])
readfile 函数读入一个文件并写入到输出缓冲。该函数返回从文件中读入的字节数。如果
出错返回FALSE,并且除非是以@readfile()形式调用,否则会显示错误信息。
该函数首先打开目标文件,并且将文件的内容输出到标准输出,如浏览器中,然后关闭
该文件。使用该函数比较简单,不需要打开和关闭文件。
实例 5-9 读取整个文件
本实例使用readfile 函数读取整个文件的内容,如代码5-11 所示。
【代码 5-11】 readfile.php

<?php
 readfile("hello/student.txt");
 ?>


代码5-11 比较简单,直接读取student.txt 文件中的数据,并显示在浏览器中,运行结果
如图5-11 所示。
图 5-11 readfile.php 文件执行结果
(2)fpassthru()函数。fpassthru 函数输出文件指针处的所有剩余数据,该函数的声明如下:
int fpassthru (resource handle)
该函数将给定的文件指针从当前的位置读取到EOF 并把结果写到输出缓冲区。如果发生
错误,fpassthru()返回FALSE。否则fpassthru()返回从handle 读取并传递到输出的字符数目。
如果既不修改文件也不在特定位置检索,只想将文件的内容下载到输出缓冲区,应该使
用readfile(),这样可以省去fopen()调用。
第5 章 PHP 中的文件处理技术 171
提示
当在 Windows 系统中将fpassthru()用于二进制文件时,要确保在用fopen()
打开文件时在mode 中附加了“b”选项来将文件以二进制方式打开。建议在处
理二进制文件时使用“b”标志,这样可以使脚本的移植性更好。
同 readfile 相比,fpassthru 需要首先打开文件,数据读取完毕还需要关闭文件。另外
fpassthru 函数是读取当前指针之后的所有数据。假如当前指针已经在文件的中间,则只是输
出所有后面的数据。
实例 5-10 读取当前指针后的全部文件内容
本实例演示了如何通过fpassthru 函数读取当前指针后的全部内容,如代码5-12 所示。
【代码 5-12】 fpassthru.php

<?php
 $filename = 'hello/student.txt';
 $handle = fopen ($filename, "r");
 $buffer = fgets ($handle,1024); //首先读取一行,移动指针
 //接着调用fpassthru 输出剩下内容
 fpassthru($handle);
 fclose($handle);
 ?>


fpassthru.php 的执行结果如图5-12 所示。
图 5-12 fpassthru.php 文件执行结果
从图 5-12 可以看出,由于在代码中首先调用了fgets 函数读取了一行,因此接着调用
fpassthru 函数,只会输出接下来的两行内容(读者可以对比图5-11 和图5-12)。
实例 5-11 向浏览器发送图像
本实例用来向浏览器输出一幅图像,如代码5-13 所示。
【代码 5-13】 fpassthru_pic.php

<?php
 $filename = 'hello/1.bmp';
 $handle = fopen ($filename, "rb"); //二进制读取数据,使用rb 模式
 //发送html 头,表示发送二进制数据
 header("Content-Type: image/png");
 //filesize 为获取文件大小,在后面介绍
 header("Content-Length: ".filesize($filename));
 //输出图像数据到浏览器
 fpassthru($handle);
 exit;
 ?>


172 PHP 网络编程技术与实例
fpassthru_pic.php 文件的执行结果如图5-13 所示。
图 5-13 fpassthru_pic.php
(3)file()函数。file 函数也是读取整个文件的内容,但是该函数会把整个文件读入一个
数组中。file 函数的声明如下:
array file ( string filename [, int use_include_path [, resource context]])
和readfile()一样,只是file()将文件作为一个数组返回。数组中的每个单元都是文件中相
应的一行,包括换行符在内。如果失败,file()返回FALSE。如果想在include_path 中搜寻文
件,可以将可选参数use_include_path 设为“1”。
提示
返回的数组中每一行都包括了行结束符,因此,如果不需要行结束符,可以
使用trim()函数。
实例 5-12 将整个文件读入到数组
本实例使用file 函数将整个文件读入到数组并输出,如代码5-14 所示。
【代码 5-14】 file.php

<?php
 // 将一个文件读入数组,这里读取的是远程文件
 $lines = file ('http://www.sohu.com');
 // 在数组中循环,显示html 的源文件并加上行号
 foreach ($lines as $line_num => $line) {
 echo "Line #<b>{$line_num}</b> : " . htmlspecialchars($line) . "<br>\n";
 }
 ?>


file.php 文件的执行结果如图5-14 所示。
图 5-14 file.php 文件的执行结果
代码 5-14 通过函数file 打开sohu 网站的首页,然后将获取的内容按行编号输出。从代
码中很容易理解,file 函数是将整个文件的内容按行保存在了数组中。
第5 章 PHP 中的文件处理技术 173
(4)file_get_contents 函数。file_get_contents 函数将整个文件作为一个字符串读入。该函
数的声明如下:
string file_get_contents ( string filename [, int use_include_path [, resource
context]])
file_get_contents()函数是将文件的内容读入到一个字符串中的首选方法。将在参数offset
所指定的位置开始读取长度为maxlen 的内容。如果失败,file_get_contents()将返回FALSE。
如果操作系统支持还会使用内存映射技术来增强性能。除了file_get_contents()将文件返回为
一个字符串以外,其余与file()的使用一样。
提示 该函数适用于二进制对象。
实例 5-13 将整个文件读入到字符串
本实例使用file_get_contents 函数将文件读入到字符串,如代码5-15 所示。
【代码 5-15】 file_get_contents.php

<?php
 // 将文件作为字符串读入到一个变量中
 $lines = file_get_contents ('hello/student.txt');
 //输出内容
 echo $lines;
 ?>


file_get_contents.php 的执行结果如图5-15 所示。
图 5-15 file_get_contents.php 文件的执行结果
5.5.3 读取一个字符
很多时候需要对整个文件的每个字符进行分析,如查找、替换部分内容等。PHP 也提供
了相应的函数用来逐个读取数据。
(1)fgetc()函数。fgetc()函数从文件指针中读取字符,该函数的声明如下:
string fgetc (resource handle)
该函数返回包含有一个字符的字符串,该字符从handle 指向的文件中得到。碰到文件结
束即EOF 为真,否则返回FALSE。
实例 5-14 读入单个字符
本实例使用fgetc 函数读入文件中的单个字符,如代码5-16 所示。
【代码 5-16】 fgetc.php

<?php
 $fp = fopen('hello/4.txt', 'r');
 174 PHP 网络编程技术与实例
 if (!$fp) {
 echo '不能打开文件!';
 }
 while (false !== ($char = fgetc($fp))) {
 echo "$char";
 }
 fclose($fp);
 ?>


fgetc.php 通过fgetc 函数逐个读取文件4.txt 中的字符。
注意
如果文件中包含有中文,则可能不能正确显示结果。因为一个中文字符包
含两个字节,而fgetc 通常只会读取一个字节的字符。
5.5.4 读取任意长度函数
另外一个读取文件的函数fread(),能够从文件中读取指定长度的数据。该函数的声明
如下:
string fread ( int handle, int length)
fread()从文件指针handle 读取最多length 个字节。该函数在读取完length 个字节数,或
到达EOF 的时候,或(对于网络流)当一个包可用时就会停止读取文件。同时该函数也能够
读取二进制文件。
实例 5-15 读入指定长度的字符串
本实例演示了fread 函数的应用,如代码5-17 所示。
【代码 5-17】 fread.php

<?php
 $fp = fopen('hello/4.txt', 'r');
 //读取文件的前10 个字符
 $contents = fread($fp, 10);
 echo $contents."<br><br>";
 fclose($fp);
 //读取网络数据包数据
 $handle = fopen ("http://www.sohu.com/", "rb");
 $contents = "";
 do {
 $data = fread($handle, 8192);
 if (strlen($data) == 0) {
 break;
 }
 $contents .= $data;
 } while(true);
 echo $contents;
 fclose ($handle);
 ?>


第5 章 PHP 中的文件处理技术 175
fread.php 的运行结果如图5-16 所示。
图 5-16 fread.php 文件的执行结果
代码 5-17 首先从4.txt 文件读取了指定的10 个字符,然后打开远程文件下载数据。这里
打开的是搜狐的主页。
提示
上例比使用while(!feof())的方法性能要好,因为在每个循环中节约了函数
调用的花费。
5.5.5 文件定位
前面虽然介绍了逐行读取数据、逐个字符读取数据等,但是通过这些函数来定位文件指
针效率比较低。PHP 中有专门进行文件定位的函数。
(1)rewind()函数。rewind 函数将文件位置指针设为文件流的开头,其声明如下:
bool rewind ( resource handle)
如果成功则返回TRUE,失败则返回FALSE。文件指针必须合法,并且指向由fopen()
成功打开的文件。
提示
如果将文件以附加("a")模式打开,写入文件的任何数据总是会被附加在
后面,不管文件指针的位置。
实例 5-16 将文件指针指向文件头
本实例演示了rewind 函数的应用,如代码5-18 所示。
【代码 5-18】 rewind.php

<?php
 $handle = fopen ("hello/student.txt", "r");
 //首先读取第一行
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 //读取第二行
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 //将指针回到文件开始,继续读取一行数据,将读取到第一行数据
 rewind($handle);
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 fclose ($handle);
 ?>


rewind.php 的执行结果如图5-17 所示。
176 PHP 网络编程技术与实例
图 5-17 rewind.php 文件的执行结果
从图 5-18 可以看出,在使用rewind 函数之后,指针又回到了文件开始,所以最后一行
为文件的第一行数据。
(2)fseek()函数。fseek()函数用于文件指针定位,该函数的声明如下:
int fseek ( resource handle, int offset [, int whence])
fseek 函数在文件中设定文件指针位置。新指针的位置,从文件头开始以字节数度量,是
在参数whence 指定的位置加上offset。
whence 的值定义如下。
SEEK_SET:设定位置等于offset 字节。
SEEK_CUR:设定位置为当前位置加上offset。
SEEK_END:设定位置为文件尾加上offset(要移动到文件尾之前的位置,需要给offset
传递一个负值)。
如果没有指定 whence,默认为SEEK_SET。
如果函数调用成功则返回 0;否则返回−1。
注意 移动到 EOF 之后的位置不算错误。
实例 5-17 设定文件指针位置
本实例演示了fseek 函数的应用,如代码5-19 所示。
【代码 5-19】 fseek.php

<?php
 $handle = fopen ("hello/5.txt", "r");
 //首先读取第一行,读取完毕后,指针在第一行最后
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 //接着将指针向后移动5 个字节,因为是相对当前位置,所以需要设定SEEK_CUR 参数
 fseek($handle,5,SEEK_CUR);
 //接着读取一行
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 //将指针回到文件开始,重新读取第一行,因为是绝对位置为0,
 //则不用设置whence 参数默,默认的whence 是SEEK_SET,表示绝对位置
 fseek($handle,0);
 //读取一行数据,因为指针回到文件开始,所以会读取第一行数据
 $buffer = fgets($handle,1024);
 echo $buffer . "<br>";
 fclose ($handle);
 ?>


fseek.php 文件的执行结果如图5-18 所示。
第5 章 PHP 中的文件处理技术 177
图 5-18 fseek.php 文件的执行结果
代码 5-19 打开了文件5.txt,然后先读取第一行数据,接着将指针向后移动5,读取第二
行中第5 个字符后面剩下的字符。然后将指针设置为文件开始,并获取一行数据。
5.txt 的文件内容如下所示:
1.I woke up this morning with a buzz rollin' 'round in my brain
2.I haven't been drinkin' but it feels pretty good just the same
3.It must be contagious-looks like it's goin' around
从上面可以看出,rewind 函数等于一个0 偏移量的fseek 函数。
(3)ftell()函数。ftell 函数并不起实际的定位作用,而是报告当前文件指针的位置。该函
数的声明如下:
int ftell(resource handle)
返回由handle 指定的文件指针的位置,即文件流中的偏移量。如果出错,返回FALSE。
实例 5-18 获取文件指针位置
本实例演示了ftell 函数的应用,如代码5-20 所示。
【代码 5-20】 ftell.php

<?php
 // 打开文件并读些数据
 $fp = fopen("hello/5.txt", "r");
 //获得前15 个字符
 $data = fgets($fp, 15);
 // 获取当前指针
 echo ftell($fp); // 输出当前位置
 fclose($fp);
 ?>


代码5-20 的输出结果为14,因为之前已经获取了15 个字符,而指针从0 开始计算,所
以当前位置为14。