tmpfile() 函数用于创建一个具有唯一文件名的临时文件,并返回一个文件句柄。该临时文件会在关闭(使用 fclose())或脚本结束时自动删除。
这个函数非常适合需要临时存储数据但不需要持久化保存的场景。由于文件会自动清理,减少了忘记删除临时文件导致磁盘空间浪费的风险。
tmpfile ( ) : resource|false
参数说明:
fwrite()、fread() 等false,通常是由于以下原因:
fclose() 或脚本结束时自动删除。
创建临时文件并写入/读取数据:
<?php
// 创建临时文件
$tempHandle = tmpfile();
if ($tempHandle !== false) {
echo "临时文件创建成功<br>";
// 写入数据
fwrite($tempHandle, "这是临时文件内容\n");
fwrite($tempHandle, "第二行数据\n");
// 重置文件指针到开头
rewind($tempHandle);
// 读取数据
echo "文件内容:<br>";
while (!feof($tempHandle)) {
echo fgets($tempHandle) . "<br>";
}
// 获取文件信息
$fileStats = fstat($tempHandle);
echo "文件大小:" . $fileStats['size'] . " 字节<br>";
// 关闭文件(会自动删除)
fclose($tempHandle);
echo "文件已关闭并自动删除";
} else {
echo "无法创建临时文件";
}
?>
使用临时文件处理大量数据:
<?php
// 模拟处理大量数据
function processLargeData($dataGenerator) {
// 创建临时文件
$tempHandle = tmpfile();
if ($tempHandle === false) {
throw new RuntimeException('无法创建临时文件');
}
$totalBytes = 0;
// 写入生成的数据
foreach ($dataGenerator as $chunk) {
$bytesWritten = fwrite($tempHandle, $chunk);
$totalBytes += $bytesWritten;
}
// 处理完成后,重置指针并读取
rewind($tempHandle);
$results = [];
while (!feof($tempHandle)) {
$line = fgets($tempHandle);
if ($line !== false) {
$results[] = trim($line);
}
}
// 获取文件统计信息
$stats = fstat($tempHandle);
// 关闭文件(自动删除)
fclose($tempHandle);
return [
'results' => $results,
'total_bytes' => $totalBytes,
'file_size' => $stats['size'],
'line_count' => count($results)
];
}
// 模拟数据生成器
function generateData($lines = 1000) {
for ($i = 0; $i < $lines; $i++) {
yield "数据行 #" . ($i + 1) . ": " . uniqid() . "\n";
}
}
// 使用示例
try {
$result = processLargeData(generateData(500));
echo "处理完成!<br>";
echo "写入字节数:" . $result['total_bytes'] . "<br>";
echo "文件大小:" . $result['file_size'] . " 字节<br>";
echo "行数:" . $result['line_count'] . "<br>";
echo "临时文件已自动清理";
} catch (Exception $e) {
echo "错误:" . $e->getMessage();
}
?>
使用临时文件处理二进制数据:
<?php
// 创建临时文件处理二进制数据
$tempHandle = tmpfile();
if ($tempHandle) {
// 写入二进制数据
$binaryData = pack('C*', 0x48, 0x65, 0x6C, 0x6C, 0x6F); // "Hello" 的二进制
fwrite($tempHandle, $binaryData);
// 重置指针
rewind($tempHandle);
// 读取二进制数据
$readData = fread($tempHandle, 1024);
// 转换为十六进制显示
$hexData = '';
for ($i = 0; $i < strlen($readData); $i++) {
$hexData .= sprintf('%02X ', ord($readData[$i]));
}
echo "二进制数据(十六进制):" . trim($hexData) . "<br>";
echo "文本表示:" . $readData . "<br>";
// 也可以使用bin2hex
echo "使用bin2hex:" . bin2hex($readData) . "<br>";
fclose($tempHandle);
}
?>
使用临时文件处理CSV数据:
<?php
function processCSVData($csvRows) {
$tempHandle = tmpfile();
if (!$tempHandle) {
return false;
}
// 写入CSV标题
fputcsv($tempHandle, ['ID', 'Name', 'Email', 'Score']);
// 写入数据行
foreach ($csvRows as $row) {
fputcsv($tempHandle, $row);
}
// 重置指针并读取处理
rewind($tempHandle);
$processed = [];
$isHeader = true;
$header = [];
while (($row = fgetcsv($tempHandle)) !== false) {
if ($isHeader) {
$header = $row;
$isHeader = false;
continue;
}
// 处理数据:例如,只保留分数大于60的行
if (isset($row[3]) && $row[3] > 60) {
$processed[] = array_combine($header, $row);
}
}
// 如果需要,可以将处理后的数据写回临时文件
rewind($tempHandle);
ftruncate($tempHandle, 0); // 清空文件
fputcsv($tempHandle, $header);
foreach ($processed as $row) {
fputcsv($tempHandle, array_values($row));
}
// 获取最终结果
rewind($tempHandle);
$finalCSV = stream_get_contents($tempHandle);
fclose($tempHandle);
return [
'processed_count' => count($processed),
'csv_data' => $finalCSV
];
}
// 使用示例
$csvData = [
[1, '张三', 'zhangsan@example.com', 85],
[2, '李四', 'lisi@example.com', 45],
[3, '王五', 'wangwu@example.com', 92],
[4, '赵六', 'zhaoliu@example.com', 58]
];
$result = processCSVData($csvData);
if ($result) {
echo "处理完成!保留 " . $result['processed_count'] . " 条记录<br>";
echo "<pre>" . htmlspecialchars($result['csv_data']) . "</pre>";
}
?>
确保临时文件被正确关闭:
<?php
// 使用try-finally确保文件关闭
function withTempFile($callback) {
$tempHandle = tmpfile();
if ($tempHandle === false) {
throw new RuntimeException('无法创建临时文件');
}
try {
return $callback($tempHandle);
} finally {
// 无论是否发生异常,都会关闭文件
if (is_resource($tempHandle)) {
fclose($tempHandle);
}
}
}
// 使用示例
try {
$result = withTempFile(function($handle) {
// 写入大量数据
for ($i = 0; $i < 10000; $i++) {
fwrite($handle, "Line $i: " . uniqid() . "\n");
}
// 模拟可能出错的操作
if (rand(0, 10) === 0) {
throw new Exception('模拟的随机错误');
}
// 返回处理结果
rewind($handle);
$lineCount = 0;
while (!feof($handle)) {
fgets($handle);
$lineCount++;
}
return ['line_count' => $lineCount];
});
echo "处理成功,行数:" . $result['line_count'] . "<br>";
echo "临时文件已自动清理";
} catch (Exception $e) {
echo "发生错误:" . $e->getMessage() . "<br>";
echo "临时文件已自动清理";
}
?>
| 特性 | tmpfile() | tempnam() |
|---|---|---|
| 函数签名 | tmpfile(): resource|false |
tempnam(dir, prefix): string|false |
| 返回值 | 文件句柄(resource) | 文件路径(string) |
| 文件打开模式 | w+(读写模式) | 不打开文件,只创建空文件 |
| 自动删除 | 是(关闭时或脚本结束时) | 否(需要手动 unlink()) |
| 文件位置 | 系统临时目录 | 可以指定目录 |
| 文件名前缀 | 系统生成,不可控 | 可以指定前缀 |
| 使用场景 | 临时数据处理,不需要保留文件 | 需要文件路径,或需要自定义目录/前缀 |
| 安全性 | 较高(自动清理) | 较低(需要手动清理) |
<?php
// tmpfile() 示例
echo "tmpfile() 示例:<br>";
$tmpfileHandle = tmpfile();
fwrite($tmpfileHandle, "tmpfile数据");
rewind($tmpfileHandle);
echo "内容:" . fread($tmpfileHandle, 1024) . "<br>";
// 文件会在fclose()或脚本结束时自动删除
echo "<br>tempnam() 示例:<br>";
$tempnamPath = tempnam(sys_get_temp_dir(), 'myprefix_');
echo "文件路径:" . $tempnamPath . "<br>";
file_put_contents($tempnamPath, "tempnam数据");
echo "内容:" . file_get_contents($tempnamPath) . "<br>";
// 需要手动删除
unlink($tempnamPath);
echo "文件已手动删除";
fclose($tmpfileHandle); // tmpfile文件自动删除
?>
tmpfile() 创建的临时文件会在以下情况下自动删除:
| 清理时机 | 描述 |
|---|---|
fclose() 调用时 |
显式关闭文件句柄时立即删除 |
| 脚本正常结束时 | PHP脚本执行完成后自动清理 |
| 脚本异常终止时 | 即使脚本因错误或异常终止,文件通常也会被清理 |
| 资源被垃圾回收时 | 当文件句柄变量超出作用域且被PHP垃圾回收时 |
<?php
// 演示自动清理机制
function demonstrateCleanup() {
echo "创建临时文件...<br>";
$handle = tmpfile();
if ($handle) {
$meta = stream_get_meta_data($handle);
echo "临时文件路径:" . $meta['uri'] . "<br>";
fwrite($handle, "测试数据");
echo "已写入数据<br>";
// 检查文件是否存在
clearstatcache();
echo "文件存在:" . (file_exists($meta['uri']) ? '是' : '否') . "<br>";
// 不调用 fclose(),让脚本结束时自动清理
echo "不显式关闭文件句柄...<br>";
// 文件会在函数返回、变量销毁或脚本结束时自动清理
}
}
demonstrateCleanup();
// 此时临时文件可能还未被清理,因为句柄变量仍在作用域中
echo "<br>函数已返回,但文件句柄变量仍在作用域中<br>";
// 显式清理
echo "<br>现在显式清理所有tmpfile资源:<br>";
// 创建多个临时文件但不关闭
$handles = [];
for ($i = 0; $i < 3; $i++) {
$handle = tmpfile();
if ($handle) {
$meta = stream_get_meta_data($handle);
echo "创建临时文件 #" . ($i + 1) . ": " . $meta['uri'] . "<br>";
$handles[] = $handle;
}
}
// 显式关闭所有句柄
foreach ($handles as $handle) {
fclose($handle); // 立即删除文件
}
echo "所有临时文件已显式关闭并删除<br>";
?>
fclose()<?php
// 1. 总是检查返回值
$handle = tmpfile();
if ($handle === false) {
// 处理错误
throw new RuntimeException('无法创建临时文件');
}
// 2. 使用try-finally确保清理
try {
// 使用临时文件
fwrite($handle, "数据");
rewind($handle);
// ... 其他操作
} finally {
if (is_resource($handle)) {
fclose($handle);
}
}
// 3. 处理二进制数据时使用二进制函数
function processBinaryData() {
$handle = tmpfile();
if (!$handle) return false;
// 写入二进制数据
$binary = random_bytes(1024); // 生成随机二进制数据
fwrite($handle, $binary);
// 读取时使用fread而不是文本函数
rewind($handle);
$data = fread($handle, 1024);
fclose($handle);
return $data;
}
// 4. 监控资源使用
function monitorTempfileUsage() {
$startMemory = memory_get_usage();
$startTime = microtime(true);
$handle = tmpfile();
fwrite($handle, str_repeat('x', 1024 * 1024)); // 写入1MB数据
$peakMemory = memory_get_peak_usage();
$endTime = microtime(true);
fclose($handle);
return [
'memory_used' => $peakMemory - $startMemory,
'time_elapsed' => $endTime - $startTime
];
}
?>
<?php
class DataConverter {
public function convertFormat($inputData, $fromFormat, $toFormat) {
// 创建临时文件存储原始数据
$tempHandle = tmpfile();
if (!$tempHandle) {
throw new RuntimeException('无法创建临时文件');
}
try {
// 写入原始数据
if ($fromFormat === 'json') {
fwrite($tempHandle, json_encode($inputData));
} elseif ($fromFormat === 'csv') {
foreach ($inputData as $row) {
fputcsv($tempHandle, $row);
}
} else {
fwrite($tempHandle, serialize($inputData));
}
// 转换处理
rewind($tempHandle);
$converted = $this->performConversion($tempHandle, $fromFormat, $toFormat);
return $converted;
} finally {
fclose($tempHandle);
}
}
private function performConversion($handle, $fromFormat, $toFormat) {
// 根据格式进行转换
if ($fromFormat === 'json' && $toFormat === 'array') {
rewind($handle);
$json = stream_get_contents($handle);
return json_decode($json, true);
}
// 其他转换逻辑...
return null;
}
}
// 使用示例
$converter = new DataConverter();
$data = [
['name' => '张三', 'age' => 25],
['name' => '李四', 'age' => 30]
];
$result = $converter->convertFormat($data, 'array', 'json');
echo "转换结果:" . json_encode($result);
?>
<?php
class ImageProcessor {
public function applyFilter($imagePath, $filterType) {
// 加载图像
$image = imagecreatefromjpeg($imagePath);
if (!$image) {
throw new RuntimeException('无法加载图像');
}
// 创建临时文件存储处理结果
$tempHandle = tmpfile();
if (!$tempHandle) {
imagedestroy($image);
throw new RuntimeException('无法创建临时文件');
}
try {
// 应用滤镜
if ($filterType === 'grayscale') {
imagefilter($image, IMG_FILTER_GRAYSCALE);
} elseif ($filterType === 'blur') {
imagefilter($image, IMG_FILTER_GAUSSIAN_BLUR);
}
// 将图像写入临时文件
imagejpeg($image, stream_get_meta_data($tempHandle)['uri'], 90);
// 将临时文件内容读入内存(或直接输出)
rewind($tempHandle);
$imageData = stream_get_contents($tempHandle);
return [
'data' => $imageData,
'size' => strlen($imageData),
'type' => 'image/jpeg'
];
} finally {
// 清理资源
imagedestroy($image);
fclose($tempHandle);
}
}
}
// 使用示例
$processor = new ImageProcessor();
try {
$result = $processor->applyFilter('input.jpg', 'grayscale');
echo "图像处理完成,大小:" . $result['size'] . " 字节";
// 可以将 $result['data'] 保存到文件或直接输出
} catch (Exception $e) {
echo "错误:" . $e->getMessage();
}
?>