array|false fstat ( resource $handle )
| 参数 | 描述 |
|---|---|
handle |
文件指针资源,通常由fopen()函数创建 |
| 键名 | 数字索引 | 描述 | 示例值 |
|---|---|---|---|
dev |
0 | 设备号 | 2050 |
ino |
1 | inode号 | 123456 |
mode |
2 | inode保护模式(权限) | 33204 |
nlink |
3 | 链接数 | 1 |
uid |
4 | 所有者的用户ID | 1000 |
gid |
5 | 所有者的组ID | 1000 |
rdev |
6 | 设备类型(如果是inode设备) | 0 |
size |
7 | 文件大小(字节) | 1024 |
atime |
8 | 最后访问时间(Unix时间戳) | 1635678900 |
mtime |
9 | 最后修改时间(Unix时间戳) | 1635678800 |
ctime |
10 | 最后改变时间(Unix时间戳) | 1635678700 |
blksize |
11 | 文件系统I/O的块大小 | 4096 |
blocks |
12 | 分配的512字节块数 | 8 |
<?php
// 创建测试文件
$filename = 'test.txt';
file_put_contents($filename, 'Hello, World! This is a test file.');
// 打开文件
$handle = fopen($filename, 'r');
if (!$handle) {
die('无法打开文件');
}
// 获取文件状态信息
$stat = fstat($handle);
if ($stat === false) {
die('无法获取文件状态');
}
// 输出所有信息
echo "<h5>文件状态信息:</h5>";
echo "<pre>" . print_r($stat, true) . "</pre>";
// 访问特定信息
echo "<h5>关键信息:</h5>";
echo "文件大小: " . $stat['size'] . " 字节<br>";
echo "最后修改时间: " . date('Y-m-d H:i:s', $stat['mtime']) . "<br>";
echo "最后访问时间: " . date('Y-m-d H:i:s', $stat['atime']) . "<br>";
echo "权限模式: " . decoct($stat['mode']) . " (八进制)<br>";
fclose($handle);
unlink($filename);
?>
<?php
// 获取文件类型和权限的辅助函数
function getFileTypeFromMode($mode) {
$type = $mode & 0xF000; // 文件类型位
switch ($type) {
case 0xC000: return 'socket';
case 0xA000: return 'symbolic link';
case 0x8000: return 'regular file';
case 0x6000: return 'block device';
case 0x4000: return 'directory';
case 0x2000: return 'character device';
case 0x1000: return 'FIFO (named pipe)';
default: return 'unknown';
}
}
function getPermissionString($mode) {
$permissions = '';
// 所有者权限
$permissions .= (($mode & 0x0100) ? 'r' : '-');
$permissions .= (($mode & 0x0080) ? 'w' : '-');
$permissions .= (($mode & 0x0040) ? (($mode & 0x0800) ? 's' : 'x') : (($mode & 0x0800) ? 'S' : '-'));
// 组权限
$permissions .= (($mode & 0x0020) ? 'r' : '-');
$permissions .= (($mode & 0x0010) ? 'w' : '-');
$permissions .= (($mode & 0x0008) ? (($mode & 0x0400) ? 's' : 'x') : (($mode & 0x0400) ? 'S' : '-'));
// 其他用户权限
$permissions .= (($mode & 0x0004) ? 'r' : '-');
$permissions .= (($mode & 0x0002) ? 'w' : '-');
$permissions .= (($mode & 0x0001) ? (($mode & 0x0200) ? 't' : 'x') : (($mode & 0x0200) ? 'T' : '-'));
return $permissions;
}
// 测试函数
function analyzeFile($filename) {
if (!file_exists($filename)) {
return "文件不存在";
}
$handle = fopen($filename, 'r');
if (!$handle) {
return "无法打开文件";
}
$stat = fstat($handle);
fclose($handle);
if ($stat === false) {
return "无法获取文件状态";
}
$result = [
'filename' => $filename,
'type' => getFileTypeFromMode($stat['mode']),
'permissions' => getPermissionString($stat['mode']),
'size' => $stat['size'],
'owner_uid' => $stat['uid'],
'owner_gid' => $stat['gid'],
'last_modified' => date('Y-m-d H:i:s', $stat['mtime']),
'last_accessed' => date('Y-m-d H:i:s', $stat['atime']),
'inode' => $stat['ino'],
'device' => $stat['dev']
];
return $result;
}
// 创建测试文件
$filename = 'example.txt';
file_put_contents($filename, 'Test content');
chmod($filename, 0644); // 设置权限
// 分析文件
$analysis = analyzeFile($filename);
if (is_array($analysis)) {
echo "<h5>文件分析结果:</h5>";
echo "<table class='table table-bordered'>";
foreach ($analysis as $key => $value) {
echo "<tr><td style='width:30%;'><strong>" . ucfirst(str_replace('_', ' ', $key)) . "</strong></td><td>$value</td></tr>";
}
echo "</table>";
}
// 清理
unlink($filename);
?>
<?php
// 创建测试文件
$filename = 'comparison.txt';
file_put_contents($filename, 'Test file for stat() vs fstat() comparison.');
echo "<h5>stat() vs fstat() 比较:</h5>";
// 使用stat()函数
echo "<h6>使用stat()函数:</h6>";
$stat1 = stat($filename);
if ($stat1 !== false) {
echo "文件大小: " . $stat1['size'] . " 字节<br>";
echo "修改时间: " . date('Y-m-d H:i:s', $stat1['mtime']) . "<br>";
}
// 使用fstat()函数
echo "<h6>使用fstat()函数:</h6>";
$handle = fopen($filename, 'r');
if ($handle) {
$stat2 = fstat($handle);
if ($stat2 !== false) {
echo "文件大小: " . $stat2['size'] . " 字节<br>";
echo "修改时间: " . date('Y-m-d H:i:s', $stat2['mtime']) . "<br>";
}
fclose($handle);
}
// 性能比较
function performanceComparison($filename, $iterations = 1000) {
$results = [];
// 测试stat()
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
stat($filename);
}
$results['stat'] = microtime(true) - $start;
// 测试fstat()
$handle = fopen($filename, 'r');
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
fstat($handle);
}
$results['fstat'] = microtime(true) - $start;
fclose($handle);
return $results;
}
// 执行性能测试
$iterations = 10000;
$perf = performanceComparison($filename, $iterations);
echo "<h6>性能比较({$iterations}次调用):</h6>";
echo "stat()耗时: " . number_format($perf['stat'], 4) . " 秒<br>";
echo "fstat()耗时: " . number_format($perf['fstat'], 4) . " 秒<br>";
// 清理
unlink($filename);
?>
<?php
class FileMonitor {
private $filename;
private $handle;
private $lastStat = null;
public function __construct($filename) {
$this->filename = $filename;
$this->handle = fopen($filename, 'r');
if (!$this->handle) {
throw new Exception("无法打开文件: {$filename}");
}
// 初始状态
$this->lastStat = $this->getCurrentStat();
}
/**
* 获取当前文件状态
*/
private function getCurrentStat() {
$stat = fstat($this->handle);
if ($stat === false) {
throw new Exception("无法获取文件状态");
}
return $stat;
}
/**
* 检查文件是否被修改
*/
public function isModified() {
$current = $this->getCurrentStat();
return $current['mtime'] !== $this->lastStat['mtime'];
}
/**
* 检查文件大小是否变化
*/
public function isSizeChanged() {
$current = $this->getCurrentStat();
return $current['size'] !== $this->lastStat['size'];
}
/**
* 检查文件是否被删除(通过inode判断)
*/
public function isDeleted() {
clearstatcache(); // 清除缓存
return !file_exists($this->filename);
}
/**
* 获取文件变化详情
*/
public function getChanges() {
$current = $this->getCurrentStat();
$changes = [];
if ($current['mtime'] !== $this->lastStat['mtime']) {
$changes['modified'] = [
'old' => $this->lastStat['mtime'],
'new' => $current['mtime'],
'old_str' => date('Y-m-d H:i:s', $this->lastStat['mtime']),
'new_str' => date('Y-m-d H:i:s', $current['mtime'])
];
}
if ($current['size'] !== $this->lastStat['size']) {
$changes['size'] = [
'old' => $this->lastStat['size'],
'new' => $current['size'],
'diff' => $current['size'] - $this->lastStat['size']
];
}
// 更新最后状态
$this->lastStat = $current;
return $changes;
}
/**
* 监控文件变化(持续监控)
*/
public function monitor($interval = 1, $maxChecks = 10) {
$changes = [];
for ($i = 0; $i < $maxChecks; $i++) {
$currentChanges = $this->getChanges();
if (!empty($currentChanges)) {
$changes[] = [
'time' => time(),
'changes' => $currentChanges
];
echo "检测到文件变化(" . date('Y-m-d H:i:s') . "):<br>";
foreach ($currentChanges as $type => $change) {
echo "- $type: " . json_encode($change) . "<br>";
}
}
sleep($interval);
}
return $changes;
}
/**
* 获取文件统计信息
*/
public function getStats() {
return $this->getCurrentStat();
}
public function __destruct() {
if ($this->handle) {
fclose($this->handle);
}
}
}
// 使用示例
try {
// 创建测试文件
$filename = 'monitored.txt';
file_put_contents($filename, 'Initial content');
// 创建监控器
$monitor = new FileMonitor($filename);
echo "<h5>初始文件状态:</h5>";
$initialStats = $monitor->getStats();
echo "文件大小: " . $initialStats['size'] . " 字节<br>";
echo "最后修改时间: " . date('Y-m-d H:i:s', $initialStats['mtime']) . "<br>";
echo "<h5>模拟文件变化:</h5>";
// 第一次修改
sleep(1);
file_put_contents($filename, 'Modified content - first change');
echo "第一次修改完成<br>";
// 检查变化
if ($monitor->isModified()) {
echo "检测到文件被修改<br>";
$changes = $monitor->getChanges();
echo "变化详情: " . json_encode($changes) . "<br>";
}
// 第二次修改
sleep(1);
file_put_contents($filename, 'Modified content - second change with more data');
echo "第二次修改完成<br>";
// 检查变化
if ($monitor->isSizeChanged()) {
echo "检测到文件大小变化<br>";
$changes = $monitor->getChanges();
echo "大小变化: " . json_encode($changes['size']) . "<br>";
}
// 清理
unlink($filename);
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
clearstatcache()清除缓存以获取最新信息stat()可以直接使用文件名lstat()专门用于符号链接| 函数 | 输入 | 输出 | 特点 | 适用场景 |
|---|---|---|---|---|
fstat() |
文件句柄 | 文件状态数组 | 需要已打开的文件句柄,性能较好 | 已打开文件的信息获取 |
stat() |
文件路径 | 文件状态数组 | 直接使用文件名,自动解析符号链接 | 常规文件信息获取 |
lstat() |
文件路径 | 文件状态数组 | 专门用于符号链接,不跟随链接 | 符号链接信息获取 |
stat() - 给出文件的信息lstat() - 给出文件或符号链接的信息clearstatcache() - 清除文件状态缓存fileperms() - 取得文件权限fileowner() - 取得文件的所有者filegroup() - 取得文件的组filesize() - 取得文件大小filemtime() - 取得文件修改时间fileatime() - 取得文件访问时间filectime() - 取得文件的inode修改时间监控文件是否被修改、删除或权限变更,用于日志轮转、配置文件监控等。
检查文件的权限设置,确保安全性和访问控制。
在需要多次访问同一文件信息时,使用fstat()比stat()更高效。
通过比较文件的mtime和size,判断文件是否需要同步或更新。