在PHP开发中,文件操作是一个非常基础但又非常重要的技能。无论是读取配置文件、写入日志、上传文件、生成缓存,还是处理用户上传的文件,都需要用到文件操作。
PHP提供了丰富的文件操作函数,可以完成文件的创建、打开、读取、写入、删除、复制、移动、重命名等各种操作。同时,PHP也提供了目录操作函数,可以创建、删除、遍历目录。
今天分享PHP文件操作的详解,从基础到进阶,帮你掌握PHP文件操作的各种技巧。
文件的基本操作
1. 判断文件是否存在
$file = 'test.txt';
if (file_exists($file)) {
echo "文件存在";
} else {
echo "文件不存在";
}fileexists()函数可以判断文件或目录是否存在。如果只判断文件,可以用isfile();如果只判断目录,可以用is_dir()。
if (is_file($file)) { echo "是文件"; }
if (is_dir($file)) { echo "是目录"; }2. 打开文件
$file = 'test.txt';
$handle = fopen($file, 'r'); // 只读方式打开fopen()函数用于打开文件,第二个参数是打开模式:
r:只读,文件指针在开头r+:读写,文件指针在开头w:只写,文件指针在开头,清空文件内容,文件不存在则创建w+:读写,文件指针在开头,清空文件内容,文件不存在则创建a:只写,文件指针在末尾,追加写入,文件不存在则创建a+:读写,文件指针在末尾,追加写入,文件不存在则创建x:只写,文件不存在则创建,存在则报错x+:读写,文件不存在则创建,存在则报错
注意:打开文件后,用完要记得用fclose()关闭文件。
3. 读取文件
方式一:fread读取指定长度
$handle = fopen('test.txt', 'r');
$content = fread($handle, filesize('test.txt')); // 读取整个文件
fclose($handle);方式二:fgets逐行读取
$handle = fopen('test.txt', 'r');
while (!feof($handle)) {
$line = fgets($handle); // 读取一行
echo $line;
}
fclose($handle);方式三:fgetc逐字符读取
$handle = fopen('test.txt', 'r');
while (!feof($handle)) {
$char = fgetc($handle); // 读取一个字符
echo $char;
}
fclose($handle);方式四:filegetcontents读取整个文件(推荐)
$content = file_get_contents('test.txt'); // 读取整个文件到字符串filegetcontents()是最简单的读取文件方式,不需要手动打开和关闭文件。它也可以读取远程文件(URL)。
方式五:file读取文件到数组
$lines = file('test.txt'); // 读取文件到数组,每个元素是一行
foreach ($lines as $line) {
echo $line;
}4. 写入文件
方式一:fwrite写入
$handle = fopen('test.txt', 'w');
fwrite($handle, 'Hello World'); // 写入内容
fclose($handle);方式二:fileputcontents写入(推荐)
file_put_contents('test.txt', 'Hello World'); // 写入文件fileputcontents()是最简单的写入方式,不需要手动打开和关闭文件。如果文件不存在,会自动创建;如果文件存在,会覆盖原有内容。
追加写入:
file_put_contents('test.txt', 'Hello World', FILE_APPEND); // 追加写入同时加锁:
file_put_contents('test.txt', 'Hello World', FILE_APPEND | LOCK_EX); // 追加写入并加锁5. 删除文件
$file = 'test.txt';
if (unlink($file)) {
echo "文件删除成功";
} else {
echo "文件删除失败";
}6. 复制文件
$source = 'test.txt';
$dest = 'test_copy.txt';
if (copy($source, $dest)) {
echo "文件复制成功";
} else {
echo "文件复制失败";
}7. 重命名/移动文件
$oldName = 'test.txt';
$newName = 'new_test.txt';
if (rename($oldName, $newName)) {
echo "文件重命名成功";
} else {
echo "文件重命名失败";
}rename()也可以用来移动文件,把文件移动到另一个目录。
文件属性操作
1. 获取文件大小
$file = 'test.txt';
$size = filesize($file); // 文件大小,单位字节
echo "文件大小:" . $size . "字节";
// 格式化显示
function formatSize($size) {
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$i = 0;
while ($size >= 1024 && $i < 4) {
$size /= 1024;
$i++;
}
return round($size, 2) . $units[$i];
}
echo formatSize(filesize($file));2. 获取文件修改时间
$file = 'test.txt';
$mtime = filemtime($file); // 文件修改时间,时间戳
echo "修改时间:" . date('Y-m-d H:i:s', $mtime);
$atime = fileatime($file); // 文件访问时间
$ctime = filectime($file); // 文件创建时间(Windows)/ inode修改时间(Linux)3. 获取文件权限
$file = 'test.txt';
$perms = fileperms($file); // 文件权限
echo "权限:" . decoct($perms & 0777); // 八进制显示4. 判断文件类型
$file = 'test.txt';
echo filetype($file); // 文件类型:file、dir、link等
is_file($file); // 是否是文件
is_dir($file); // 是否是目录
is_link($file); // 是否是符号链接
is_readable($file); // 是否可读
is_writable($file); // 是否可写
is_executable($file); // // 是否可执行5. 获取文件信息
$file = 'test.txt';
$info = stat($file); // 获取文件详细信息
print_r($info);
$pathinfo = pathinfo($file); // 获取路径信息
echo $pathinfo['dirname']; // 目录名
echo $pathinfo['basename']; // 文件名(含扩展名)
echo $pathinfo['extension']; // 扩展名
echo $pathinfo['filename']; // 文件名(不含扩展名)目录操作
1. 创建目录
$dir = 'new_dir';
if (mkdir($dir)) {
echo "目录创建成功";
} else {
echo "目录创建失败";
}
// 递归创建多级目录
mkdir('a/b/c', 0777, true); // 递归创建a/b/c目录2. 删除目录
$dir = 'new_dir';
if (rmdir($dir)) {
echo "目录删除成功";
} else {
echo "目录删除失败";
}注意:rmdir()只能删除空目录,如果目录中有文件或子目录,需要先删除里面的内容。
3. 遍历目录
方式一:opendir/readdir
$dir = 'uploads';
if (is_dir($dir)) {
if ($handle = opendir($dir)) {
while (($file = readdir($handle)) !== false) {
if ($file != '.' && $file != '..') {
echo $file . "\n";
}
}
closedir($handle);
}
}方式二:scandir(推荐)
$dir = 'uploads';
$files = scandir($dir); // 读取目录内容到数组
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
echo $file . "\n";
}
}方式三:glob(按模式匹配)
$files = glob('uploads/*.jpg'); // 匹配uploads目录下所有jpg文件
foreach ($files as $file) {
echo $file . "\n";
}
$files = glob('uploads/*'); // 匹配uploads目录下所有文件和目录方式四:RecursiveDirectoryIterator(递归遍历)
$dir = new RecursiveDirectoryIterator('uploads');
$iterator = new RecursiveIteratorIterator($dir);
foreach ($iterator as $file) {
echo $file->getPathname() . "\n";
}4. 递归删除目录
function deleteDir($dir) {
if (!is_dir($dir)) return false;
$files = scandir($dir);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
$path = $dir . '/' . $file;
if (is_dir($path)) {
deleteDir($path); // 递归删除子目录
} else {
unlink($path); // 删除文件
}
}
}
return rmdir($dir); // 删除空目录
}
deleteDir('uploads');5. 递归复制目录
function copyDir($source, $dest) {
if (!is_dir($source)) return false;
if (!is_dir($dest)) mkdir($dest, 0777, true);
$files = scandir($source);
foreach ($files as $file) {
if ($file != '.' && $file != '..') {
$srcPath = $source . '/' . $file;
$destPath = $dest . '/' . $file;
if (is_dir($srcPath)) {
copyDir($srcPath, $destPath); // 递归复制子目录
} else {
copy($srcPath, $destPath); // 复制文件
}
}
}
return true;
}
copyDir('source_dir', 'dest_dir');文件上传
文件上传是PHP开发中常见的需求,比如用户头像上传、图片上传、文件分享等。
1. HTML表单
<form action="upload.php" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="上传">
</form>注意:文件上传表单必须设置enctype="multipart/form-data",method必须是post。
2. PHP处理上传
if ($_FILES['file']['error'] == UPLOAD_ERR_OK) {
$tmpName = $_FILES['file']['tmp_name']; // 临时文件名
$name = $_FILES['file']['name']; // 原始文件名
$size = $_FILES['file']['size']; // 文件大小
$type = $_FILES['file']['type']; // 文件类型
$uploadDir = 'uploads/';
$dest = $uploadDir . basename($name);
if (move_uploaded_file($tmpName, $dest)) {
echo "文件上传成功";
} else {
echo "文件上传失败";
}
} else {
echo "上传错误:" . $_FILES['file']['error'];
}3. 上传安全
文件上传有安全风险,一定要做好安全检查:
$allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
$maxSize = 2 * 1024 * 1024; // 2MB
if ($_FILES['file']['error'] != UPLOAD_ERR_OK) {
die("上传错误");
}
if ($_FILES['file']['size'] > $maxSize) {
die("文件太大");
}
if (!in_array($_FILES['file']['type'], $allowedTypes)) {
die("文件类型不允许");
}
// 检查文件扩展名
$ext = pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION);
$allowedExts = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array(strtolower($ext), $allowedExts)) {
die("文件扩展名不允许");
}
// 检查是否是真实图片
if (!getimagesize($_FILES['file']['tmp_name'])) {
die("不是真实图片");
}
// 生成安全的文件名
$newName = uniqid() . '.' . $ext;
$dest = 'uploads/' . $newName;
if (move_uploaded_file($_FILES['file']['tmp_name'], $dest)) {
echo "上传成功:" . $newName;
}文件锁
当多个进程同时读写同一个文件时,可能会出现数据不一致的问题。这时候需要用文件锁。
$file = 'data.txt';
$handle = fopen($file, 'a+');
if (flock($handle, LOCK_EX)) { // 排他锁(写入锁)
fwrite($handle, "新内容\n");
fflush($handle); // 刷新输出
flock($handle, LOCK_UN); // 释放锁
} else {
echo "无法获取锁";
}
fclose($handle);锁的类型:
LOCK_SH:共享锁(读取锁),多个进程可以同时持有LOCK_EX:排他锁(写入锁),只能有一个进程持有LOCK_UN:释放锁LOCK_NB:非阻塞锁,获取不到锁时不等待
用fileputcontents()时,可以用LOCK_EX参数加锁:
file_put_contents('data.txt', '内容', LOCK_EX);常用技巧和最佳实践
- 优先使用filegetcontents和fileputcontents:这两个函数简单易用,不需要手动打开和关闭文件,适合大多数场景。
- 大文件用fopen/fread/fwrite:处理大文件时,不要一次性读取整个文件,用fopen/fread逐块读取,避免内存溢出。
- 检查文件是否存在:操作文件前,先检查文件是否存在,避免报错。
- 处理文件路径:用
DIRECTORY_SEPARATOR处理跨平台路径,或者统一用/(Windows也支持)。 - 文件上传安全:文件上传一定要做安全检查,验证文件类型、大小、扩展名,生成安全的文件名,上传到web根目录外或禁止执行。
- 文件权限:注意文件和目录的权限设置,不要设置过高的权限(如0777),避免安全风险。
- 错误处理:文件操作可能失败,要做好错误处理,检查返回值。
- 关闭文件:用fopen打开的文件,用完一定要fclose关闭,避免资源泄漏。
- 使用文件锁:多进程同时写文件时,要用文件锁,避免数据冲突。
- 清理临时文件:上传的临时文件、生成的临时文件,用完要及时清理,避免占用磁盘空间。
常见问题
1. 文件权限不足
报错:Permission denied 解决:检查文件和目录的权限,确保PHP有读写权限。Linux下用chmod修改权限,Windows下检查文件夹权限。
2. 文件路径错误
报错:No such file or directory 解决:检查文件路径是否正确,用绝对路径或正确的相对路径。可以用DIR获取当前目录,拼接路径。
3. 大文件内存溢出
报错:Allowed memory size exhausted 解决:不要一次性读取大文件,用fopen/fread逐块读取,或者用生成器(Generator)处理。
4. 文件上传失败
常见原因:
- 表单没有设置
enctype="multipart/form-data" - 文件大小超过
uploadmaxfilesize或postmaxsize - 上传目录没有写入权限
- 临时目录没有写入权限
解决:检查php.ini配置,检查目录权限,检查表单设置。
5. 中文文件名乱码
解决:设置文件系统编码,Windows下用iconv()转换编码,或者用英文/数字文件名。
总结
PHP文件操作是PHP开发的基础技能,掌握它能让你处理各种文件相关的需求。
核心要点:
- 基本操作:file_exists判断、fopen打开、fread/fgets读取、fwrite写入、fclose关闭、unlink删除、copy复制、rename重命名
- 简便函数:filegetcontents读取、fileputcontents写入、scandir遍历目录、glob模式匹配
- 文件属性:filesize大小、filemtime修改时间、fileperms权限、pathinfo路径信息、stat详细信息
- 目录操作:mkdir创建、rmdir删除、opendir/readdir遍历、递归删除/复制
- 文件上传:HTML表单、$FILES处理、moveuploaded_file、安全检查
- 文件锁:flock加锁,避免多进程冲突
- 最佳实践:用简便函数、大文件逐块读、检查存在、处理路径、上传安全、权限设置、错误处理
希望这篇文章能帮你掌握PHP文件操作,让你的开发更加高效。
评论(0)
暂无评论,快来抢沙发~
评论功能仅对会员开放,请先登录
登录