文件和文件夹操作

移动 | 复制 | 删除 | 重命名 | 下载

<?php

namespace Framework\Tools;
use PharData; class FileManager
{
// 提示信息配置
private $messages = array(
'file_list_success' => '获取成功。',
'file_list_failure' => '获取失败。',
'not_exist' => '文件夹不存在。',
'duplicate_name' => '文件或文件夹名称已存在。',
'not_duplicate_name' => '文件或文件夹名称不存在。',
'file_name' => '文件名称已存在.',
'folder_name' => '文件夹名称已存在。',
'copy_success' => '复制成功。',
'copy_failure' => '复制失败。',
'move_success' => '移动成功。',
'move_failure' => '移动失败。',
'rename_success' => '重命名成功。',
'rename_failure' => '重命名失败。',
'recycle_duplicate_name' => '回收站中已存在当前文件或文件夹。',
'delete_to_recycle_success' => '成功移动到回收站。',
'delete_to_recycle_failure' => '移动到回收站失败。'
); // 存储最近一次操作的消息
private $lastMessage = ''; /**
* 设置提示信息
*
* @param array $messages 自定义提示信息数组,键为消息类型,值为具体消息内容
* @return void
*/
public function setMessages($messages)
{
$this->messages = array_merge($this->messages, $messages);
} /**
* 获取最近一次操作的消息
*
* @return string 最近一次操作的提示消息
*/
public function getLastMessage()
{
return $this->lastMessage;
} /**
* 获取当前文件夹下的所有文件夹及子文件夹的树形结构
*
* @param string $dir 目录路径
* @return array
*/
public function getDirectoryTree($dir, $path = '')
{
$result = [];
if (!is_dir($dir)) {
$this->lastMessage = $this->messages['not_exist'];
return $result;
}
$cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value, [".", ".."])) {
$fullPath = $dir . DIRECTORY_SEPARATOR . $value;
if (is_dir($fullPath)) {
$result[] = [
'label' => $value, // 文件夹名称
'path' => $path ? str_replace($path, '', $fullPath) : $fullPath,
'children' => $this->getDirectoryTree($fullPath, $path),
];
}
}
}
$this->lastMessage = $this->messages['file_list_success'];
return $result;
} /**
* 获取指定文件夹下的所有文件(可配置后缀名过滤)
*
* @param string $dir 目录路径
* @param array $allowedExtensions 允许的文件后缀名(可选)
* @return array
*/
public function getFilesInDirectory($dir, $allowedExtensions = [])
{
$files = []; if (!file_exists($dir) && !is_dir($dir)) {
$this->lastMessage = $this->messages['not_exist'];
return $files;
} $cdir = scandir($dir);
foreach ($cdir as $key => $value) {
if (!in_array($value, [".", ".."]) && is_file($dir . DIRECTORY_SEPARATOR . $value)) {
// 如果没有设置后缀名过滤,或者文件后缀名在允许的列表中
if (empty($allowedExtensions) || $this->isFileExtensionAllowed($value, $allowedExtensions)) {
$files[] = $value;
}
}
}
$this->lastMessage = $this->messages['file_list_success'];
return $files;
} /**
* 检查文件后缀名是否在允许的列表中
*
* @param string $fileName 文件名
* @param array $allowedExtensions 允许的后缀名列表
* @return bool
*/
public function isFileExtensionAllowed($fileName, $allowedExtensions)
{
$extension = pathinfo($fileName, PATHINFO_EXTENSION);
return in_array(strtolower($extension), array_map('strtolower', $allowedExtensions));
} /**
* 递归删除目录及其内容
*
* @param string $dir 目录路径
* @return bool 是否删除成功
*/
private function deleteDir($dir)
{
if (!is_dir($dir)) return false;
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') continue;
$fullPath = "$dir/$item";
is_dir($fullPath) ? $this->deleteDir($fullPath) : unlink($fullPath);
}
return rmdir($dir);
} /**
* 删除文件夹
* emptyTheRecycleBin 是否清空回收站
* @param string $dir
* @return bool
*/
public function deleteDirectory($dir)
{
if (!file_exists($dir)) {
return true;
} if (!is_dir($dir)) {
return unlink($dir);
} foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') {
continue;
} if (!$this->deleteDirectory($dir . DIRECTORY_SEPARATOR . $item)) {
return false;
}
} return rmdir($dir);
} /**
* 复制单个或多个文件或文件夹
*
* @param string|array $sources 要复制的源文件或文件夹路径,可以是单个路径字符串或路径数组
* @param string $destination 目标文件夹路径
* @return bool 操作成功返回 true,失败返回 false
*/
public function copy($sources, $destination)
{ if (!$this->validateSources($sources, $destination)) {
return false;
}
if (!is_array($sources)) {
$sources = array($sources);
}
foreach ($sources as $source) {
if (is_file($source)) {
if (!copy($source, $destination . '/' . basename($source))) {
$this->lastMessage = $this->messages['copy_failure'];
return false;
}
} elseif (is_dir($source)) {
if (!$this->recursiveCopy($source, $destination . '/' . basename($source))) {
$this->lastMessage = $this->messages['copy_failure'];
return false;
}
}
}
$this->lastMessage = $this->messages['copy_success'];
return true;
} /**
* 递归复制文件夹
*
* @param string $source 源文件夹路径
* @param string $destination 目标文件夹路径
* @return bool 复制成功返回 true
*/
private function recursiveCopy($source, $destination)
{
if (!is_dir($destination)) {
mkdir($destination);
}
$dir = opendir($source);
while (($file = readdir($dir)) !== false) {
if ($file != '.' && $file != '..') {
if (is_dir($source . '/' . $file)) {
$this->recursiveCopy($source . '/' . $file, $destination . '/' . $file);
} else {
copy($source . '/' . $file, $destination . '/' . $file);
}
}
}
closedir($dir);
return true;
} /**
* 移动单个或多个文件或文件夹
*
* @param string|array $sources 要移动的源文件或文件夹路径,可以是单个路径字符串或路径数组
* @param string $destination 目标文件夹路径
* @return bool 操作成功返回 true,失败返回 false
*/
public function move($sources, $destination)
{
if (!$this->validateSources($sources, $destination)) {
return false;
}
if (!is_array($sources)) {
$sources = array($sources);
}
foreach ($sources as $source) {
if (!rename($source, $destination . '/' . basename($source))) {
$this->lastMessage = $this->messages['move_failure'];
return false;
}
}
$this->lastMessage = $this->messages['move_success'];
return true;
} /**
* 重命名文件或文件夹
*
* @param string $path 要重命名的文件或文件夹的当前路径
* @param string $newName 新的名称
* @return bool 重命名成功返回 true,失败返回 false
*/
public function rename($path, $newName)
{
$dir = dirname($path);
if (file_exists($dir . '/' . $newName)) {
$this->lastMessage = $this->messages['duplicate_name'];
return false;
}
if (!rename($path, $dir . '/' . $newName)) {
$this->lastMessage = $this->messages['rename_failure'];
return false;
}
$this->lastMessage = $this->messages['rename_success'];
return true;
} /**
* 生成唯一的文件名
*
* @param string $baseName 基础文件名
* @param string $recycleBin 回收站目录
* @return string 唯一的文件名
*/
private function getUniqueFileName($baseName, $recycleBin)
{
$nameInfo = pathinfo($baseName);
$name = $nameInfo['filename'];
$ext = isset($nameInfo['extension']) ? '.' . $nameInfo['extension'] : '';
$counter = 1;
$newName = $baseName;
while (file_exists($recycleBin . '/' . $newName)) {
$newName = $name . " ($counter)" . $ext;
$counter++;
}
return $newName;
} /**
* 删除文件或文件夹到回收站
*
* @param string|array $sources 要删除到回收站的文件或文件夹路径,可以是单个路径字符串或路径数组
* @param string $recycleBin 回收站目录
* @return bool 操作成功返回 true,失败返回 false
*/
public function deleteToRecycle($sources, $recycleBin)
{
if (!is_array($sources)) {
$sources = array($sources);
}
foreach ($sources as $source) {
$baseName = basename($source);
if (!file_exists($source)) {
$this->lastMessage = $this->messages['not_duplicate_name'];
return false;
}
$uniqueName = $this->getUniqueFileName($baseName, $recycleBin);
$destination = $recycleBin . '/' . $uniqueName;
if (!rename($source, $destination)) {
$this->lastMessage = $this->messages['delete_to_recycle_failure'];
return false;
}
}
$this->lastMessage = $this->messages['delete_to_recycle_success'];
return true;
} /**
* 验证源文件或文件夹是否可以操作
*
* @param string|array $sources 要验证的源文件或文件夹路径,可以是单个路径字符串或路径数组
* @param string $destination 目标文件夹路径
* @return bool 验证通过返回 true,存在重名情况返回 false
*/
private function validateSources($sources, $destination)
{
if (!is_array($sources)) {
$sources = array($sources);
} if (!file_exists($destination) && !is_dir($destination)) {
$this->lastMessage = $this->messages['not_exist'];
return false;
} foreach ($sources as $source) {
if (file_exists($destination . '/' . basename($source))) {
if (is_file($destination . '/' . basename($source))) {
$this->lastMessage = $this->messages['file_name'];
} elseif (is_dir($destination . '/' . basename($source))) {
$this->lastMessage = $this->messages['folder_name'];
} else {
$this->lastMessage = $this->messages['duplicate_name'];
}
return false;
}
}
return true;
} /**
* 获取文件详细信息
*
* @param string $filePath
* @return array
*/
public function getFileDetails($filePath)
{
return [
'size' => filesize($filePath),
'last_modified' => date("Y m d H:i:s.", filemtime($filePath)),
'type' => filetype($filePath),
'extension' => pathinfo($filePath, PATHINFO_EXTENSION),
];
} /**
* 获取文件夹详细信息
*
* @param string $dir
* @return array
*/
public function getDirectoryDetails($dir)
{
return [
'size' => $this->getDirectorySize($dir),
'last_modified' => date("Y m d H:i:s.", filemtime($dir)),
'type' => filetype($dir),
];
} /**
* 计算文件夹大小
*
* @param string $dir
* @return int
*/
private function getDirectorySize($dir)
{
$size = 0;
foreach (scandir($dir) as $item) {
if ($item == '.' || $item == '..') {
continue;
} $path = $dir . DIRECTORY_SEPARATOR . $item;
if (is_file($path)) {
$size += filesize($path);
} else {
$size += $this->getDirectorySize($path);
}
}
return $size;
} /**
* 下载文件或文件夹
*
* @param array|string $paths 文件或文件夹路径(可以是单个路径或路径数组)
* @param string $archiveName 打包下载的文件名(可选)
* @return bool
*/
public function download($paths, $archiveName = 'download.tar.gz')
{
if (empty($paths)) {
return $this->returnError("没有文件可供下载");
} // 如果是单个文件,直接下载
if (is_string($paths)) {
if (!file_exists($paths)) {
return $this->returnError("文件不存在");
}
$this->downloadFile($paths);
return true;
} // 如果是多个文件或文件夹,检查是否存在
foreach ($paths as $path) {
if (!file_exists($path)) {
return $this->returnError("文件或文件夹不存在");
}
} // 打包下载
$this->downloadAsTarGz($paths, $archiveName);
return true;
} /**
* 下载文件或图片的方法
*
* @param string $filePath 文件的完整路径
* @param string $fileName 下载时显示的文件名,默认为空
* @return void
*/
private function downloadFile($filePath, $fileName = '')
{
// 检查文件是否存在
if (!file_exists($filePath)) {
http_response_code(404);
die("文件不存在");
} // 如果没有提供文件名,则使用文件的原始名称
$fileName = $fileName ?: basename($filePath); // 获取文件的 MIME 类型
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$mimeType = finfo_file($finfo, $filePath);
finfo_close($finfo); // 设置响应头
header('Content-Description: File Transfer');
header('Content-Type: ' . $mimeType);
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($filePath)); // 开启输出缓冲
ob_clean();
flush(); // 读取并输出文件内容
readfile($filePath); // 终止脚本执行
exit;
} /**
* 打包下载多个文件或文件夹为 tar.gz 格式
*
* @param array $paths 文件或文件夹路径数组
* @param string $archiveName 打包下载的文件名
*/
private function downloadAsTarGz($paths, $archiveName = 'download.tar.gz')
{
// 创建临时文件
$archivePath = sys_get_temp_dir() . '/' . $archiveName; // 使用 Linux 命令打包
if ($this->isLinux()) {
$fileList = implode(' ', array_map('escapeshellarg', $paths));
exec("tar -czf '{$archivePath}' -C " . dirname($paths[0]) . " " . $fileList);
if (file_exists($archivePath)) {
$this->downloadFile($archivePath, $archiveName);
unlink($archivePath); // 删除临时文件
exit;
} else {
die("打包文件失败");
}
} // 使用 PHP 打包
$phar = new PharData($archivePath);
foreach ($paths as $path) {
if (is_dir($path)) {
$phar->buildFromDirectory($path);
} else {
$phar->addFile($path, basename($path));
}
} if (file_exists($archivePath)) {
$this->downloadFile($archivePath, $archiveName);
unlink($archivePath); // 删除临时文件
exit;
} else {
die("打包文件失败");
}
} /**
* 判断是否是 Linux 系统
*
* @return bool
*/
private function isLinux()
{
return strtoupper(substr(PHP_OS, 0, 3)) === 'LIN';
} /**
* 返回错误信息
*
* @param string $message 错误信息
* @return bool
*/
private function returnError($message)
{
echo $message;
return false;
} }

php文件和文件夹操作类的更多相关文章

  1. c# 封装的文件夹操作类之复制文件夹

    c#  封装的文件夹操作类之复制文件夹 一.复制文件夹原理: 1.递归遍历文件夹 2.复制文件 二.FolderHelper.cs /// <summary> /// 文件夹操作类 /// ...

  2. [IO] C# DirFileHelper文件与文件夹操作类教程与源码下载 (转载)

    点击下载 DirFileHelper.zip 主要功能如下所示 // 摘要: // 向文本文件的尾部追加内容 // // 参数: // filePath: // 文件的绝对路径 // // conte ...

  3. [No0000DC]C# FileHelper 本地文件、文件夹操作类封装FileHelper

    using System; using System.Diagnostics; using System.IO; using System.Text; using Shared; namespace ...

  4. FileOperator 文件(夹)操作类

    public class FileOperator { /** * 复制文件目录 * @param srcDir 要复制的源目录 eg:/mnt/sdcard/DB * @param destDir ...

  5. 一个获取google chrome扩展crx文件信息的PHP操作类

    此类中实现了从crx文件获取扩展的Appid.获取manifest.json文件内容.将crx文件转换为一般zip文件 代码如下: <?php class CrxParserException ...

  6. 背水一战 Windows 10 (85) - 文件系统: 获取文件夹和文件, 分组文件夹, 排序过滤文件夹和文件, 搜索文件

    [源码下载] 背水一战 Windows 10 (85) - 文件系统: 获取文件夹和文件, 分组文件夹, 排序过滤文件夹和文件, 搜索文件 作者:webabcd 介绍背水一战 Windows 10 之 ...

  7. Java-编写一个jdbc操作类

    1.通过读取文件配置 package 数据库操作类; /* * Db.java Created on 2007年8月20日, 上午 8:37 */ import java.io.*; import j ...

  8. Java中创建操作文件和文件夹的工具类

    Java中创建操作文件和文件夹的工具类 FileUtils.java import java.io.BufferedInputStream; import java.io.BufferedOutput ...

  9. 文件及文件夹操作- File类、Directory 类、FileInfo 类、DirectoryInfo 类

    文件及文件夹操作: C/S:WinForm可以操作客户端文件 Client ServerB/S:Brower Server 命名空间:using system .IO; 1. File类: 创建:Fi ...

  10. JAVA文件操作类和文件夹的操作代码示例

    JAVA文件操作类和文件夹的操作代码实例,包括读取文本文件内容, 新建目录,多级目录创建,新建文件,有编码方式的文件创建, 删除文件,删除文件夹,删除指定文件夹下所有文件, 复制单个文件,复制整个文件 ...

随机推荐

  1. dectron2框架export导出并使用 onnx 记录

    python tools/deploy/export_model.py \ --sample-image /Users/gatilin/PycharmProjects/model-graphviz-p ...

  2. 微服务实战系列(五)-注册中心Eureka与nacos区别-copy

    1. 场景描述 nacos最近用的比较多,介绍下nacos及部署吧,刚看了下以前写过类似的,不过没写如何部署及与eureka区别,只展示了效果,补补吧. 2.解决方案 2.1 nacos与eureka ...

  3. 微服务测试 Dubbo 接口测试

    微服务测试 Dubbo 接口测试 URL:https://blog.csdn.net/qq_35759632/article/details/80832932 微服务测试 ----Dubbo 接口测试 ...

  4. Collection接口方法

     Collection 接口继承树 Collection 接口Collection 接口是 List.Set 和 Queue 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 ...

  5. .NET Core 中如何构建一个弹性的 HTTP 请求机制?

    1. 理解弹性 HTTP 请求机制 什么是弹性? 弹性是指系统在面对故障或异常情况时,能够保持或快速恢复到正常状态的能力.在 HTTP 请求的上下文中,弹性意味着当请求失败时,系统能够自动采取一系列措 ...

  6. 魔乐社区体验:探索Llama 3.1模型微调之旅

    在2024年的AI领域,Meta发布的Llama 3.1模型无疑成为了研究者和开发者的新宠.我有幸通过魔乐社区提供的资源,对这一模型进行了深入的学习和实践.在这个过程中,魔乐社区的资源和支持给我留下了 ...

  7. wsgi服务器

    wsgi服务器DRP原则:Don't repeat yourself1.wsgi接口:全称 Web Server Gateway Interface (web服务器网关接口) 请求:request 响 ...

  8. Windows中安装和配置Maven

    1.下载 下载地址:https://maven.apache.org/download.cgi 下载文件:https://dlcdn.apache.org/maven/maven-3/3.9.6/bi ...

  9. 具体数学第六章习题选做(genshining)

    11.对于 \(n\ge 0\),求以下式子的封闭形式. \[\sum_k(-1)^k{n\brack k} \] 由于 \[\sum{n\brack k}x^k=x^{\overline n} \] ...

  10. 推荐一款人人可用的开源 BI 工具,更符合国人使用习惯的数据可视化分析工具,数据大屏开发神器!

    前言 今天大姚给大家推荐一款人人可用的开源.免费的 BI 工具,更符合国人使用习惯的数据可视化分析工具,数据大屏开发神器,Tableau.帆软的开源替代:DataEase. 工具介绍 DataEase ...