访问文件的机制发生了彻底的变化。在PHP4.3.0以前,每一个文件类型(本地、压缩、远程)都有不同的执行方式。但是,通过引入流处理,与一个文件的每一次交互都使用流处理层,它抽象访问特殊对象的“文件”的执行细节。流处理层可以让你使用一个URL流从一个HTTP资源创建一个GD图片对象,处理压缩过文件,或者从一个问价拷贝到另一个文件。你可以在拷贝过程中通过执行一个用户流处理或者过滤来应用你自己的转换。
文件访问(File Access)
让我们从基础的文件访问函数开始。最初,这些函数只能处理一些常规的文件。所以他们的名字是用“f”开始的,但是PHP把它扩展到几乎所有的功能。最常用的文件访问函数有:
fopen()。打开一个本地文件的句柄,或者一个来自URL的文件。
fread()。从一个文件读取一个数据块。
fgets()。从一个文件读取一个单独的行。
fwrite()/fputs()。写一个数据块到一个文件中。
fclose()。关闭打开的文件句柄。
feof()。如果文件到达末尾则返回真。
处理文件是非常简单的,就像下面的例子所示:
<?php
$fp = fopen('data.dat','r');
if (!$fp)
{
die ("this file could not be opened");
}
$line = fgets($fp);
fclose($fp);
在第2行中,一个文件句柄($fp)被关联到流,流被关联到硬盘中的counter.dat文件。第一个参数是文件的路径。传递到fopen()的第二个参数的模式。模式指定一个流打开的目的是为了读取、写入、即读取又写入或者为了添加。可用的模式如下:
r。用只读模式打开流。文件指针定位在流的开始处。
r+。用读取和写入模式打开流。文件指针定位在流的开始出。
w。用只写模式打开流。文件被清空并且文件指正定位在流的开始处。如果文件不存在,将尝试创建该文件。
w+。用读取和写入模式打开流。文件被清空并且文件指针定位子啊流的开始处。如果文件不存在,将尝试创建该文件。
a。用只写模式打开流。文件指针定位在流的结束处。如果文件不存在。将尝试创建该文件。
a+。用读取和写入模式打开流。文件指针定位在流的结束处。如果文件不存在,将尝试创建该文件。
“b”修饰符可以和模式一起使用以便指定文件是二进制类型的。Windows系统是区分文本和二进制文件的;如果你在Windows的二进制文件中没有使用“b”修饰符,你的文件可能会遇到错误。因此,为了让你的脚本子啊windows下通用,明智的做法是在处理一个二进制文件时总是使用“b“修饰符,甚至是你咋不要求如此的系统上开发代码时,在UNIX操作系统里面(Linux、FreeBSD、MacOSX等),”b“修饰符没有任何作用。下面是另一个小例子:
<?php
$fp = fopen("/Users/admin/Desktop/my/PHP5/fileAndStreams/data.dat","rb+");
$block = fread($fp,4096);
fwrite($fp,$block);
fclose($fp);
第三个可选的参数,true,可以在fopen()中使用以便告诉PHP到你的include路径去寻找文件,下面的脚本首先尝试从/etc打开php.ini(用只读模式),然后从/usr/local/etc打开,并且最后从当前目录进行查找(路径设置中的点表示当前目录)。因为php.ini不是一个二进制文件,我们不需要在模式中使用”b“修饰符:
<?php
ini_set('include_path','/etc:/usr/local/etc:.');
$fp = fopen('php.ini','r',true);
while (!feof($fp))
{
$line = trim(fgets($fp,256));
echo ">$line<\n";
}
fclose($fp);
该脚本使用了feof(),他是一个我们还未见过的函数,feof()检查在最后一次fread()或者fgets()调用中文件是否到达尾部。这里我们使用fgets()。把256作为第二个参数。这个数字将指定fgets()获取的行最大长度。小心的选择这个大小是非常重要的。PHP在读取之前将分配这个大小的内存,所以如果你设定的值为1000000,PHP将分配1MB的内存,尽管你的数据行只有12个字符的长度。默认值是1024字节,这个值对于大部分应用来说已经足够了。
在处理一个文件的时候最好考虑下你是否真的需要把整个文件都加载到内存中。加入你需要臊面一个文档文件,以便查找一个通过正则表达式定义的语句出现情况。如果通过fileget-contents()函数将把文件加载到内存并且接来下运行preg_match_all()函数,你很有可能浪费大量的资源。使用一个while(!feof($fp)){$line = fgets($fp); }循环的话讲更加高效,它不会应为加载一个文件而浪费内存。它也会提高正则表达式匹配的速度。