Skip to content

PHP 文件打开/读取

PHP 文件处理:打开、读取、关闭

Section titled “PHP 文件处理:打开、读取、关闭”

PHP 提供了强大的函数来与服务器的文件系统进行交互。本章介绍使用流函数打开、读取和关闭文件的基本操作。

对于简单的操作,如将整个文件读取到字符串中或将字符串写入文件,可以考虑使用更简单的 file_get_contents() 和 file_put_contents() 函数。但是,对于更精细的控制(例如逐行读取、处理大型文件、使用特定模式),fopen()、fread()、fgets() 和 fclose() 函数是必不可少的。

fopen() 函数打开一个文件或 URL 并将其绑定到一个流资源。它提供了对文件如何打开的细粒度控制。

语法: fopen(string $filename, string $mode): resource|false

我们将使用一个名为 webdictionary.txt 的示例文本文件作为示例:

AJAX = Asynchronous JavaScript and XML CSS = Cascading Style Sheets HTML = Hyper Text Markup Language PHP = PHP Hypertext Preprocessor SQL = Structured Query Language SVG = Scalable Vector Graphics XML = EXtensible Markup Language

fopen() 的第一个参数是文件路径,第二个参数指定访问模式(例如,读取、写入)。fopen() 成功时返回文件指针资源,失败时返回 false。务必检查返回值。

基本示例(以读取模式打开):

<?php
declare(strict_types=1);
$filename = "webdictionary.txt";
$mode = "r"; // 只读模式打开
// 尝试打开文件
$fileHandle = fopen($filename, $mode);
// 检查是否打开失败
if ($fileHandle === false) {
// 适当地处理错误(记录日志、显示用户友好的消息)
echo "Error: Unable to open file '{$filename}'!";
exit; // 如果文件至关重要则退出脚本
} else {
echo "File '{$filename}' opened successfully.<br>";
// 继续文件操作...
// 完成后不要忘记关闭文件!
fclose($fileHandle);
echo "File closed.";
}
?>

常见文件模式:

模式描述
r只读。从文件开头开始。
r+读/写。从文件开头开始。
w只写。清除文件内容或创建新文件。从开头开始。
w+读/写。清除文件内容或创建新文件。从开头开始。
a只写(追加)。保留现有数据。从文件末尾开始。如果文件不存在则创建。
a+读/写(追加)。保留现有数据。写入从末尾开始,读取从开头开始。如果文件不存在则创建。
x只写(排他创建)。创建新文件。如果文件已存在,则返回 false 并触发 E_WARNING。
x+读/写(排他创建)。创建新文件。如果文件已存在,则返回 false 并触发 E_WARNING。
c只写。如果文件不存在则创建。如果文件存在,不清除内容,将指针放在开头。(不如 w 或 a 常用)
c+读/写。如果文件不存在则创建。如果文件存在,不清除内容,将指针放在开头。(不如 w+ 或 a+ 常用)

注意:在模式中添加 ‘b’(例如 ‘rb’, ‘wb’)有时用于二进制文件操作,尤其是在 Windows 上,以防止换行符的转换。在类 Unix 系统上,‘b’ 通常被忽略。

fread() 函数从打开的文件指针中读取指定数量的字节。

语法: fread(resource $handle, int $length): string|false

第一个参数是由 fopen() 返回的文件句柄,第二个参数是要读取的最大字节数。

示例:读取 webdictionary.txt 的全部内容

<?php
declare(strict_types=1);
$filename = "webdictionary.txt";
// 打开前检查文件是否存在且可读
if (!is_readable($filename)) {
die("Error: File '{$filename}' does not exist or is not readable.");
}
$fileHandle = fopen($filename, "r");
if ($fileHandle === false) {
die("Error: Unable to open file '{$filename}'!");
}
// 获取文件大小以读取全部内容
$fileSize = filesize($filename);
// 处理潜在的空文件或 filesize 错误
if ($fileSize > 0) {
$content = fread($fileHandle, $fileSize);
if ($content === false) {
echo "Error reading from file.";
} else {
// 在 HTML 上下文安全地显示内容
echo "<pre>" . htmlspecialchars($content, ENT_QUOTES, 'UTF-8') . "</pre>";
}
} elseif ($fileSize === 0) {
echo "File is empty.";
} else {
echo "Error getting file size.";
}
fclose($fileHandle);
?>

注意:结合 filesize() 使用 fread() 读取整个文件很常见,但对于非常大的文件要谨慎,因为它会将整个内容加载到内存中。对于大型文件,最好在循环中分块读取。

fclose() 函数关闭一个打开的文件指针,释放资源。

语法: fclose(resource $handle): bool

fclose() 接受文件句柄资源作为参数。成功时返回 true,失败时返回 false。

fgets() 函数从打开的文件指针中读取单行。

语法: fgets(resource $handle, ?int $length = null): string|false

它读取最多 length - 1 字节,直到遇到换行符(\n),或直到到达文件末尾(EOF),以先发生者为准。如果省略 length 或为 null,则读取直到行尾。

示例:输出 webdictionary.txt 的第一行

<?php
declare(strict_types=1);
$filename = "webdictionary.txt";
$fileHandle = fopen($filename, "r");
if ($fileHandle === false) {
die("Unable to open file!");
}
// 读取第一行
$line = fgets($fileHandle);
if ($line === false) {
echo "Error reading line or end of file reached.";
} else {
echo "First line: " . htmlspecialchars($line, ENT_QUOTES, 'UTF-8');
}
fclose($fileHandle);
?>

重要:调用 fgets() 后,内部文件指针会前进到下一行的开头。

feof() 函数检查文件指针是否已到达文件末尾。

语法: feof(resource $handle): bool

当需要逐行或逐个字符地在循环中读取文件时,feof() 至关重要,尤其是在文件长度未知的情况下。

示例:逐行读取 webdictionary.txt 直到文件末尾 (EOF)

<?php
declare(strict_types=1);
$filename = "webdictionary.txt";
$fileHandle = fopen($filename, "r");
if ($fileHandle === false) {
die("Unable to open file!");
}
echo "Reading file line by line:<br>";
// 循环直到到达文件末尾
while (!feof($fileHandle)) {
$line = fgets($fileHandle);
// 检查 fgets 是否实际返回了一行(错误/EOF 时不返回 false)
if ($line !== false) {
echo htmlspecialchars($line, ENT_QUOTES, 'UTF-8') . "<br>";
}
}
fclose($fileHandle);
?>

fgetc() 函数从打开的文件指针中读取单个字符。

语法: fgetc(resource $handle): string|false

它返回读取的字符,或者在 EOF 或出错时返回 false。

示例:逐个字符读取 webdictionary.txt 直到文件末尾 (EOF)

<?php
declare(strict_types=1);
$filename = "webdictionary.txt";
$fileHandle = fopen($filename, "r");
if ($fileHandle === false) {
die("Unable to open file!");
}
echo "Reading file character by character:<br><pre>";
// 循环直到到达文件末尾
while (!feof($fileHandle)) {
$char = fgetc($fileHandle);
// 检查 fgetc 是否实际返回了一个字符
if ($char !== false) {
echo htmlspecialchars($char, ENT_QUOTES, 'UTF-8');
}
}
echo "</pre>";
fclose($fileHandle);
?>

注意:逐个字符读取通常不如逐行读取或分块读取效率高。

重要:调用 fgetc() 后,内部文件指针会移到下一个字符。

有关所有文件系统函数(包括写入(fwrite)、定位(fseek)、目录操作等)的完整参考,请查阅官方 PHP 手册:

https://www.php.net/manual/en/ref.filesystem.php

https://www.php.net/manual/en/ref.stream.php