文件和文件夹操作

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

<?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. 解读ENS网络连接,面向多云多池网络的高效互联

    本文分享自华为云社区<ENS网络连接,面向多云多池网络的高效互联>,作者:华为云Stack ENS研发团队. 1.ENS网络连接服务场景详细介绍 ENS网络连接通过统一建模和全局管控实现跨 ...

  2. c# 多线程 lock

    模拟10个线程,每个线程模拟100次取钱: 其实就是相当于1000个人来同时取钱.当然实际情况是取钱的人分布在不同的地区的取款机取钱.同一个取款机只能一个人操作. 关键是要保证取钱的余额要准确,不能在 ...

  3. 教你实现GPUImage【OpenGL渲染原理】

    一.前言 本篇主要讲解GPUImage底层是如何渲染的,GPUImage底层使用的是OPENGL,操控GPU来实现屏幕展示 由于网上OpenGL实战资料特别少,官方文档对一些方法也是解释不清楚,避免广 ...

  4. AVX512

    最近接触到SIMD编码,就不可避免的查到了AVX指令集,两者有什么关系呢,了解一下? 问:AVX是什么? 答:是一套指令集 下面具体看: AVX 以下内容主要转载自:AVX指令集是什么?它的应用又有哪 ...

  5. IDEA Spring Boot项目,排查解决maven包冲突

    一.Idea安装插件 下载方式1:插件名称:maven helper 打开Idea设置,搜索安装该插件 下载方式2:https://plugins.jetbrains.com/plugin/7179- ...

  6. FLink17--聚合函数-AggWindowApp

    一.依赖 二.代码 package net.xdclass.class11; import org.apache.flink.api.common.RuntimeExecutionMode; impo ...

  7. kvm远程管理

    列出centos7中所有的虚拟机 [root@kvm1 ~]# virsh list --all Id Name State ------------------------------------- ...

  8. C#字符串拼接的6种方式及其性能分析对比

    前言 在C#编程中字符串拼接是一种常见且基础的操作,广泛应用于各种场景,如动态生成SQL查询.构建日志信息.格式化用户显示内容等.然而,不同的字符串拼接方式在性能和内存使用上可能存在显著差异.今天咱们 ...

  9. C# Graphic 操作记录

    C# 在图片上绘制文字 /// <summary> /// 生成文字图片 /// </summary> /// <param name="text"& ...

  10. Jupyter 使用安装的虚拟环境(tensorflow)

    1. 在 anaconda 中使用 conda create -n tensorflow python=3.6 创建 tensorflow 虚拟环境: 2. 安装交互环境(ipykernel)  co ...