在本教程中,你将学习PHP中几个重要的函数,它们足以满足你所有基本的文件读写需求。你将学习如何读一个文件,写一个文件,写一个文本文件,以及检查一个文件是否存在。
作为一个PHP开发者,文件处理是你需要经常做的事情。
你可以使用PHP的文件处理函数以不同的方式来操作文件。这些函数可以用来在你的应用程序中建立一些功能,从自定义错误日志到存储缓存文件。你可以用这些函数建立的实用工具的例子有:
- 自定义日志和调试工具
- 应用程序配置存储
- 前端和应用程序的缓存
- 本地化支持
- 以及更多
幸运的是,PHP提供了很多向文件读取和写入数据的函数。在本教程中,我将向你展示从本地或远程文件中读取数据的最简单方法,以及如何使用标志来准确地写入文件。
| 章节 | 关键功能 |
|---|---|
| 检查一个文件是否存在 | file_exists(),is_file() |
| 在PHP中从一个文件中读取数据 | file_get_contents() |
| 在PHP中向文件中写入数据 | file_put_contents() |
| 读和写数据的例子 | file_get_contents(),file_put_contents() |
| 用数据流读和写到文件 | fopen(),fread(),fwrite() |
检查一个文件是否存在
当你试图从一个文件中读取数据或向它写东西时,第一步应该是检查该文件是否已经存在。试图从一个不存在的文件中读取数据将导致PHP的警告,并可能使你的代码崩溃。
检查一个文件是否存在的最简单方法是使用PHP的file_exists($filename) 函数。如果一个文件或目录与给定的$filename 存在,它将返回true ,否则返回false 。这可能是显而易见的,但我想指出,$filename 不一定只是一个文件的名称。它也可以是一个绝对或相对路径。例如,我们可以使用prim_numbers.txt或science/project/periodic_table.txt。
同样重要的是要记住,对于由于安全模式限制而无法访问的文件,这个函数也会返回false 。
另一个可以用来检查文件是否存在的函数是is_file() 。与file_exists() 相比,这个函数只在指定的路径指向一个文件而不是一个目录时返回true 。
确保文件确实存在
如果你正在编写的代码对一个特定的文件进行了大量的文件操作,你可能会使用上述函数得到不正确的结果。这是因为为了提高性能,file_exists() 和is_file() 的执行结果都被缓存了。PHP也会缓存其他文件系统函数返回的值,如filesize() ,filemtime() ,等等。
你可以调用clearstatcache() 来确保你所访问的文件的任何信息是最新的。
一般来说,只有在一个脚本中多次访问同一个文件以了解其状态时,才会出现这个问题。另外,如果你在脚本中使用unlink() 功能删除文件,缓存的数据也会被清除。这基本上意味着你可能不会面临任何与缓存有关的问题,但知道在信息变质或在试图访问一个文件的信息时得到意外的结果时可以清除缓存仍然是件好事。
在PHP中从文件中读取数据
file_get_contents() 函数
在PHP中从一个文件中读取数据的最简单的方法之一是借助于file_get_contents($filename, $use_include_path, $context, $offset, $maxlen) 函数。它将简单地读取整个文件并以字符串的形式提供给你。除了第一个参数外,所有的参数都是可选的。
第二个参数接受一个布尔值,以确定它是否应该在include路径所指定的位置寻找文件,这个路径可以用 set_include_path()函数设置。
你可以用第三个参数来指定一系列的选项来改进文件的访问方式。你可以用它来指定头的值,如Cookies 和Host ,以及HTTP方法。
$offset 参数决定了在原始文件上开始阅读的点。提供一个负值将从终点开始计算。对负偏移量的支持只在PHP7.1.0中加入。值得注意的是,offset只对本地文件有效,不支持远程文件。
file_get_contents() 函数默认为一次性读取整个文件。你可以通过为$maxlen 参数提供一个值来改变这种行为。要读取的字符长度从偏移值开始计算。
file_get_contents() 函数默认一次读取整个文件。你可以通过为$maxlen 参数提供一个值来改变这种行为。要读取的字符长度从偏移值开始计算。
你可以用这个函数来打开远程文件,但这只有在php.ini中allow-url-fopen 选项的值为true 或1 的情况下才有可能。
在PHP中向文件写入数据
file_put_contents 函数
在PHP中写数据到一个文件的最简单的方法之一是借助于file_put_contents($filename, $data, $flags, $context) 函数。
$filename 参数决定了数据将被写入哪个文件中。第二个参数是要写到文件中的数据。大多数情况下,它将是一个字符串,但也可以是一个数组或一个流资源。
记住,如果文件不存在,PHP会自动为你创建一个给定名称的文件。然而,它不会为你创建任何目录。这意味着你可以存储一个名字为On the Origin of Species [Charles Darwin].txt的文件而不会有任何错误。然而,如果将$filename 设置为Biology/Evolution/On the Origin of Species [Charles Darwin].txt,如果**Biology/Evolution/**还不存在,就会导致错误。
$flags 参数决定了内容如何被写入一个文件。它可以有以下三个值中的任何一个或全部。
**FILE_USE_INCLUDE_PATH**-这告诉PHP在include目录下搜索给定的文件名。FILE_APPEND-这将告诉PHP把你传递给函数的数据附加到文件中的现有数据上。如果你在一个文件中存储数据,如日志或个人日记,它可能很有用。记录新的数据如温度或今天发生在你身上的事件,不会覆盖你昨天记录的东西。LOCK_EX-这将告诉PHP在开始向文件中写入内容之前,先获得一个锁。它可以防止两个不同的脚本在向同一个文件读写数据时发生意外的事情。有了这个特定的值,你将得到一个对文件的独占锁。你可以在PHP文档中阅读关于这些锁的更多信息flock()函数的PHP文档中了解更多关于这些锁的信息。
这个函数在成功时返回被写入文件的字节数,失败时返回false 。然而,你仍然必须使用严格的平等运算符来检查它是否成功地将内容写入文件。这是因为向文件写入0字节的代码仍然会评估为假。
读取和写入数据的例子
在这一节中,我们将看几个真实世界的例子来证明你如何读取文件。
file_get_contents 函数
你可以去古腾堡项目网站,尝试使用file_get_contents() 函数下载文件。一旦你得到了字符串中的数据,你也可以简单地使用file_put_contents() 函数将其存储在本地文件中。下面的例子会让你明白这一点。
<?php
$filename = 'https://www.gutenberg.org/cache/epub/1228/pg1228.txt';
$book_content = file_get_contents($filename);
file_put_contents('Biology/Evolution/On the Origin of Species [Charles Darwin].txt', $book_content, LOCK_EX);
?>
现在让我们回到本地文件上。考虑这样一种情况:你有一堆文本文件,你想分析它们的内容,看看其中最常见的单词之类的东西。这可以用一堆内置的PHP函数轻松实现。
<?php
$filename = 'On the Origin of Species [Charles Darwin].txt';
$book_content = file_get_contents($filename);
$book_content_lowercase = strtolower($book_content);
$individual_words = explode(' ', $book_content_lowercase);
echo "There are about ".count($individual_words)." words in the book: ".substr($filename, 0, -4).".\n";
$word_frequency = array_count_values($individual_words);
echo "Total number of unique words in the book are ".count($word_frequency).".\n";
echo "The word 'Elephant' occurs ".$word_frequency["elephant"]." times in the book.\n";
echo "The word 'Ant' occurs ".$word_frequency["ant"]." times in the book.\n";
if(isset($word_frequency["evolution"])) {
echo "The word 'Evolution' occurs ".$word_frequency["evolution"]." times in the book.\n";
} else {
echo "The word 'Evolution' does not occur even once in the book.\n";
}
arsort($word_frequency);
echo "The most used word in the book is: '".key($word_frequency)."'.\n";
/* Output of all the code above
There are about 147520 words in the book: On the Origin of Species [Charles Darwin].
Total number of unique words in the book are 22758.
The word 'Elephant' occurs 3 times in the book.
The word 'Ant' occurs 6 times in the book.
The word 'Evolution' does not occur even once in the book.
The most used word in the book is: 'the'.
?>
我们将所有的文本转换为小写字母,并假设每一个单词都在空格处断开。然后使用explode() ,将文本转换为数组,以便更容易分析单个单词。令人惊讶的是,在整本书中,"进化 "这个词甚至没有被使用过一次,而这本书正是进化论的起源。
这只是一个自动分析大量文本的例子。你可以对存储在文件中的任何种类的文本做类似的事情。
用FILE_APPEND来记录数据
一个更有用的例子是记录小时间段的信息。它可以是你的运动程序,天气数据,或你正在观察的蜜蜂群。一旦你有了字符串中的数据,你可以很容易地将其存储在一个文件中,并使用FILE_APPEND 标志和file_put_contents() ,将其附加到现有的数据上。
<?php
$filename = "bee-colony.txt";
$present = date('l | jS \of F Y h:i:s A', time());
$entry = $present."\n";
// A pseudo function which could be replaced with something real.
$bee_information = gather_bee_data();
$entry .= "$bee_information.\n\n";
file_put_contents($filename, $entry, FILE_APPEND|LOCK_EX);
?>
你可以用一些HTML来包装文本,而不是用纯文本格式来写,以便在浏览器中更容易阅读。这种可能性是无穷无尽的。
用流读取和写入文件
PHP还有一个用于读写文件的API:fread 和fwrite 函数。
fopen()函数
fopen 函数可以让你打开一个文件进行读写,甚至可以让你创建一个新文件。
让我们看一个简单的例子来了解它是如何工作的。
<?php
$file_handle = fopen('/home/tutsplus/files/tmp.txt', 'w');
?>
在上面的例子中,fopen 函数将检查**/home/tutsplus/files/tmp.txt文件是否存在,如果存在,它将打开它进行写入。通过在第二个参数中提供'w' ,我们指定我们将向该文件写入。如果该文件不存在,它将被立即创建。这里需要注意的是,上例中的/home/tutsplus/files/**目录必须是Web服务器用户可以写入的,这样fopen 函数才能创建一个文件。
fopen 函数的第一个参数是你要打开的文件名。在上面的例子中,我们在第一个参数中提供了**/home/tutsplus/files/tmp.txt**文件名。同样,需要注意的是,我们提供了一个绝对路径名。
第二个参数是模式,它指定了你对所打开文件的访问类型。fopen 函数提供了不同的模式,你可以选择。
在我们的例子中,我们使用了w 模式,它删除了**/home/tutsplus/files/tmp.txt**的内容,只打开它进行写入。
fopen 返回一个文件系统指针,该指针用于其他文件功能,如读和写。
打开远程文件
fopen 函数并不只是用于本地文件。它也支持其他协议,可以打开来自网络上其他地方或网络上的文件。如果你在PHP中启用了allow_url_fopen 指令,你也可以打开远程文件。
<?php
$file_handle = fopen('http://your-website-url/tmp.txt', 'r');
?>
真正 重要的是要注意,当你启用allow_url_fopen 指令时,你正在创造一些安全风险,因为它为远程文件执行和其他攻击打开了大门。因此,如果你要启用这个指令,请确保你在你的应用程序中采取额外的安全措施。
fread() 函数
fread 函数允许你从一个文件中读取。它类似于fwrite ,但你需要提供你想要读取的字节长度。你还需要首先用fopen 打开文件。
fread 函数的第一个参数是文件系统指针,这样它就知道要从哪里读取。第二个参数是你想从文件中读取的长度(字节)。你需要使用fopen 函数来获得文件系统指针。
使用fread 的例子
让我们看一下下面的例子,了解它是如何工作的。
<?php
$file_handle = fopen('/home/tutsplus/files/tmp.txt', 'r');
$contents = fread($file_handle, filesize('/home/tutsplus/files/tmp.txt'));
fclose($file_handle);
?>
由于我们想从 /home/tutsplus/files/tmp.txt文件中读取数据,我们通过使用fopen 函数以r 模式打开该文件。fopen 函数做了两件事:如果一个文件不存在,它就会创建一个文件,同时也会打开它进行读或写。
接下来,我们使用fread 函数将文件的所有内容读入$content 变量。在我们的例子中,我们想读取 /home/tutsplus/files/tmp.txt文件的所有内容,因此我们使用了filesize 函数来测量该文件的大小。
fwrite 函数
fwrite 函数允许你将字符串内容写入由文件句柄引用的文件流中。
fwrite 函数的第一个参数是由fopen返回的文件系统指针 - 这是fwrite 知道要写到哪里的方法。第二个参数是我们想写进文件的字符串。
使用fwrite的例子
让我们通过下面的例子来了解fwrite 是如何工作的。
<?php
$file_handle = fopen('/home/tutsplus/files/tmp.txt', 'a+');
fwrite($file_handle, 'Tuts+ is a great online resource to learn skills you want!');
fwrite($file_handle, "\n");
fwrite($file_handle, 'Visit tutsplus.com to know more!');
fclose($file_handle);
?>
首先,我们用a+ 模式打开了 /home/tutsplus/files/tmp.txt文件,该模式为读和写打开,文件指针放在文件的最后。因此,我们的内容将被追加到文件的末尾,在任何其他内容之后。接下来,我们用fwrite 函数来写一个字符串。
正如你在上面的例子中所看到的,你可以在关闭文件之前多次使用fwrite 函数来写一系列的字符串。
最后,我们使用了fclose 函数来关闭文件。它只需要一个参数,即你要关闭的文件指针。一旦你完成了你的文件操作,通过使用fclose 函数来关闭文件总是一个好的做法。
最后的思考
在PHP中还有许多其他的读写文件的方法。但是,file_get_contents() 和file_put_contents() 几乎可以满足所有的基本需求,而不会增加不必要的复杂度。
使用file_get_contents() ,唯一可能面临的问题是当你正在读取的文件非常大时,如2GB或更大。这是因为file_get_contents() 一次性将整个文件加载到内存中,而对于这样的大文件,很有可能会耗尽内存。在这种情况下,你将不得不依赖一些函数,如 fgets()和 fread()来一次性读取文件的一小部分。