PHP fputs()函数
fputs()函数是fwrite()函数的别名,两者功能完全相同。用于向打开的文件写入数据。
重要说明:fputs()是fwrite()的历史遗留别名,建议在新代码中使用fwrite()。
语法
int|false fputs ( resource $handle , string $string [, int $length ] )
参数说明
| 参数 |
描述 |
handle |
文件指针资源,通常由fopen()函数创建 |
string |
要写入的字符串 |
length |
可选参数,指定最大写入字节数。如果指定,则只写入指定长度的字符串 |
返回值
fputs() 与 fwrite() 的关系
| 特性 |
fputs() |
fwrite() |
| 函数本质 |
fwrite()的别名 |
原始函数 |
| 函数签名 |
完全相同 |
完全相同 |
| 性能 |
完全相同 |
完全相同 |
| 推荐使用 |
不推荐,历史遗留 |
推荐,标准名称 |
| 代码可读性 |
较差,可能引起混淆 |
较好,语义明确 |
示例代码
示例1:基本文件写入
<?php
// 使用fputs()写入文件
$filename = 'test.txt';
$handle = fopen($filename, 'w');
if ($handle === false) {
die('无法打开文件');
}
// 写入字符串
$string = "Hello, World!\n";
$bytes = fputs($handle, $string);
if ($bytes === false) {
echo '写入失败';
} else {
echo "写入成功,写入字节数: $bytes<br>";
}
// 写入多行数据
fputs($handle, "这是第二行文本\n");
fputs($handle, "这是第三行文本\n");
// 关闭文件
fclose($handle);
echo "文件内容:<br>";
echo nl2br(htmlspecialchars(file_get_contents($filename)));
?>
示例2:使用length参数限制写入长度
<?php
$filename = 'limited.txt';
$handle = fopen($filename, 'w');
if ($handle) {
$text = "这是一个非常长的字符串,但是我们将只写入前一部分。";
// 只写入前10个字节
$bytes = fputs($handle, $text, 10);
echo "写入字节数: $bytes<br>";
// 关闭文件
fclose($handle);
// 显示写入的内容
$content = file_get_contents($filename);
echo "实际写入内容: " . htmlspecialchars($content) . "<br>";
echo "字符串长度: " . strlen($content) . " 字节<br>";
}
// 另一个例子:分块写入
$handle = fopen('chunks.txt', 'w');
if ($handle) {
$data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
// 每次写入5个字符
for ($i = 0; $i < strlen($data); $i += 5) {
$chunk = substr($data, $i, 5);
fputs($handle, $chunk, 5);
}
fclose($handle);
echo "<br>分块写入完成,文件内容: " . file_get_contents('chunks.txt');
}
?>
示例3:日志文件记录器
<?php
class FileLogger {
private $handle;
private $filename;
public function __construct($filename) {
$this->filename = $filename;
// 以追加模式打开文件(如果文件不存在则创建)
$this->handle = fopen($filename, 'a');
if (!$this->handle) {
throw new Exception("无法打开日志文件: $filename");
}
}
/**
* 记录日志
*/
public function log($message, $level = 'INFO') {
$timestamp = date('Y-m-d H:i:s');
$logEntry = "[$timestamp] [$level] $message\n";
// 使用fputs写入日志
$bytes = fputs($this->handle, $logEntry);
if ($bytes === false) {
throw new Exception("日志写入失败");
}
return $bytes;
}
/**
* 批量记录日志
*/
public function logBatch(array $messages, $level = 'INFO') {
$batch = '';
$timestamp = date('Y-m-d H:i:s');
foreach ($messages as $message) {
$batch .= "[$timestamp] [$level] $message\n";
}
return fputs($this->handle, $batch);
}
/**
* 获取日志文件大小
*/
public function getFileSize() {
return filesize($this->filename);
}
/**
* 清空日志文件
*/
public function clear() {
fclose($this->handle);
$this->handle = fopen($this->filename, 'w');
return $this->handle !== false;
}
public function __destruct() {
if ($this->handle) {
fclose($this->handle);
}
}
}
// 使用示例
try {
$logger = new FileLogger('app.log');
// 记录单条日志
$logger->log('应用程序启动');
$logger->log('用户登录成功', 'INFO');
$logger->log('数据库连接失败', 'ERROR');
$logger->log('用户执行了重要操作', 'WARNING');
// 批量记录
$messages = [
'批量日志条目1',
'批量日志条目2',
'批量日志条目3'
];
$logger->logBatch($messages);
echo "日志记录完成<br>";
echo "日志文件大小: " . $logger->getFileSize() . " 字节<br><br>";
// 显示日志内容
echo "<h5>日志文件内容:</h5>";
echo "<pre style='background:#f8f9fa;padding:10px;border-radius:4px;max-height:200px;overflow:auto;'>";
echo htmlspecialchars(file_get_contents('app.log'));
echo "</pre>";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
示例4:大文件生成器(性能对比)
<?php
// 生成大文件的性能对比:fputs() vs file_put_contents()
function generateLargeFile_fputs($filename, $sizeInMB) {
$start = microtime(true);
$handle = fopen($filename, 'w');
if (!$handle) {
return false;
}
$chunkSize = 1024 * 1024; // 1MB
$data = str_repeat('A', $chunkSize);
$iterations = $sizeInMB;
for ($i = 0; $i < $iterations; $i++) {
fputs($handle, $data);
}
fclose($handle);
$time = microtime(true) - $start;
return [
'method' => 'fputs',
'time' => $time,
'size' => $sizeInMB * $chunkSize
];
}
function generateLargeFile_fileputcontents($filename, $sizeInMB) {
$start = microtime(true);
$chunkSize = 1024 * 1024; // 1MB
$data = str_repeat('A', $chunkSize);
$iterations = $sizeInMB;
for ($i = 0; $i < $iterations; $i++) {
file_put_contents($filename, $data, FILE_APPEND);
}
$time = microtime(true) - $start;
return [
'method' => 'file_put_contents',
'time' => $time,
'size' => $sizeInMB * $chunkSize
];
}
// 测试生成10MB文件
$sizeMB = 10;
echo "<h5>生成 {$sizeMB}MB 文件性能对比:</h5>";
// 使用fputs
$result1 = generateLargeFile_fputs('large_fputs.dat', $sizeMB);
if ($result1) {
echo "fputs() 耗时: " . number_format($result1['time'], 4) . " 秒<br>";
echo "文件大小: " . number_format($result1['size'] / (1024*1024), 2) . " MB<br><br>";
}
// 使用file_put_contents
$result2 = generateLargeFile_fileputcontents('large_fileputcontents.dat', $sizeMB);
if ($result2) {
echo "file_put_contents() 耗时: " . number_format($result2['time'], 4) . " 秒<br>";
echo "文件大小: " . number_format($result2['size'] / (1024*1024), 2) . " MB<br><br>";
}
// 清理测试文件
@unlink('large_fputs.dat');
@unlink('large_fileputcontents.dat');
// 实际建议:对于大文件写入,使用fwrite/fputs并分块写入
function writeLargeFileEfficiently($filename, $dataGenerator, $chunkSize = 8192) {
$handle = fopen($filename, 'w');
if (!$handle) return false;
foreach ($dataGenerator() as $chunk) {
fputs($handle, $chunk, $chunkSize);
}
fclose($handle);
return true;
}
echo "<h5>高效写入大文件的模式:</h5>";
echo "使用fputs()分块写入大文件是最佳实践,可以避免内存溢出。";
?>
注意事项
重要提示:
- 别名问题:fputs()是fwrite()的别名,建议在新代码中直接使用
fwrite()以保持代码一致性
- 二进制安全:fputs()是二进制安全的,可以安全地写入包含空字符(\0)的数据
- 文件指针:写入后文件指针会移动到写入内容的末尾
- 缓冲机制:默认情况下,写入操作可能是缓冲的,使用
fflush()可以强制刷新缓冲区
- 并发写入:多个进程同时写入同一文件时,需要使用
flock()进行文件锁定
- 错误处理:始终检查返回值,失败时返回false
- 长度参数:如果指定了length参数,即使string比length长,也只会写入length个字节
- 编码问题:写入包含多字节字符(如中文)时,确保文件以正确的编码打开
- 性能考虑:对于大量小写入操作,考虑合并数据后一次性写入以提高性能
最佳实践
- 使用fwrite而非fputs:为了代码清晰和一致性,优先使用
fwrite()
- 错误处理:始终检查fputs/fwrite的返回值
- 资源管理:使用完毕后使用
fclose()关闭文件句柄
- 大文件处理:写入大文件时,分块写入避免内存溢出
- 并发控制:多进程环境使用
flock()进行文件锁定
- 缓冲优化:频繁小写入时,考虑使用输出缓冲
相关函数
| 函数 |
描述 |
与fputs()的关系 |
fwrite() |
写入文件(二进制安全) |
fputs()是fwrite()的别名 |
fopen() |
打开文件或URL |
创建fputs()所需的文件句柄 |
fclose() |
关闭打开的文件指针 |
关闭fputs()使用的文件句柄 |
file_put_contents() |
将字符串写入文件 |
更简单的文件写入函数,内部使用fwrite |
fflush() |
将缓冲内容输出到文件 |
强制刷新fputs()的缓冲区 |
ftell() |
返回文件指针位置 |
获取fputs()写入后的指针位置 |
从fputs()迁移到fwrite()
如果您有使用fputs()的旧代码,建议迁移到fwrite():
<?php
// 旧代码(使用fputs)
$handle = fopen('file.txt', 'w');
fputs($handle, 'Hello World');
fclose($handle);
// 新代码(使用fwrite)- 只需重命名函数
$handle = fopen('file.txt', 'w');
fwrite($handle, 'Hello World'); // 仅函数名不同
fclose($handle);
// 复杂的旧代码迁移示例
function oldCode($filename, $data) {
$fp = fopen($filename, 'a');
if ($fp) {
fputs($fp, $data);
fclose($fp);
return true;
}
return false;
}
function newCode($filename, $data) {
$fp = fopen($filename, 'a');
if ($fp) {
fwrite($fp, $data); // 仅此更改
fclose($fp);
return true;
}
return false;
}
?>