file_put_contents() 函数是PHP中用于将字符串写入文件的内置函数。这是写入文件内容的最常用方法之一,它封装了打开文件、写入内容和关闭文件的完整过程,使用简单且功能强大。
语法
int file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] )
参数说明
| 参数 |
描述 |
类型 |
默认值 |
是否必需 |
| filename |
要写入数据的文件名 |
string |
- |
是 |
| data |
要写入的数据,可以是字符串、数组或流资源 |
mixed |
- |
是 |
| flags |
可选。可以是以下常量的组合:
FILE_USE_INCLUDE_PATH - 在include_path中查找文件
FILE_APPEND - 追加写入,而不是覆盖
LOCK_EX - 写入时获取独占锁
|
int |
0 |
否 |
| context |
文件上下文资源,由stream_context_create()创建 |
resource |
null |
否 |
返回值
- 成功时返回写入文件的字节数
- 失败时返回 FALSE
- 如果文件不存在且目录权限允许,函数会尝试创建文件
注意事项
file_put_contents() 是写入文件内容的首选方法
- 默认会覆盖文件内容,使用
FILE_APPEND标志可追加写入
- 使用
LOCK_EX标志可以防止并发写入冲突
- 确保目录有写入权限,否则会写入失败
- 数组数据会被序列化为字符串形式写入
示例代码
示例1:基本使用 - 写入字符串到文件
<?php
// 写入字符串到文件
$data = "Hello, World!\nThis is a test file.";
$filename = 'test.txt';
$bytes_written = file_put_contents($filename, $data);
if ($bytes_written !== false) {
echo "成功写入 {$bytes_written} 字节到 {$filename}";
} else {
echo "写入文件失败";
}
?>
示例2:追加写入内容
<?php
// 追加写入内容
$data = "This line will be appended.\n";
$filename = 'log.txt';
// 使用FILE_APPEND标志追加写入
$bytes_written = file_put_contents($filename, $data, FILE_APPEND);
if ($bytes_written !== false) {
echo "成功追加 {$bytes_written} 字节到 {$filename}";
}
// 也可以使用位运算符组合多个标志
$bytes_written = file_put_contents($filename, $data, FILE_APPEND | LOCK_EX);
?>
示例3:安全并发写入(使用文件锁)
<?php
function safeWrite($filename, $data) {
// 使用LOCK_EX标志确保并发安全
$result = file_put_contents($filename, $data, LOCK_EX);
if ($result === false) {
throw new Exception("写入文件失败: {$filename}");
}
return $result;
}
// 使用示例
try {
$bytes = safeWrite('data.txt', "Important data that should not be corrupted.");
echo "安全写入 {$bytes} 字节";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
示例4:写入数组数据
<?php
// 写入数组数据
$data_array = [
'name' => 'John Doe',
'email' => 'john@example.com',
'age' => 30,
'hobbies' => ['reading', 'swimming', 'coding']
];
// 方法1:序列化数组
$serialized_data = serialize($data_array);
file_put_contents('data.ser', $serialized_data);
// 方法2:保存为JSON格式
$json_data = json_encode($data_array, JSON_PRETTY_PRINT);
file_put_contents('data.json', $json_data);
// 方法3:保存为PHP数组格式
$php_code = "<?php\nreturn " . var_export($data_array, true) . ";\n";
file_put_contents('config.php', $php_code);
echo "数据已保存为多种格式";
?>
示例5:保存错误日志
<?php
class Logger {
private $log_file;
public function __construct($log_file = 'app.log') {
$this->log_file = $log_file;
}
public function log($message, $level = 'INFO') {
$timestamp = date('Y-m-d H:i:s');
$log_entry = "[{$timestamp}] [{$level}] {$message}\n";
// 追加写入日志,使用文件锁确保并发安全
$result = file_put_contents(
$this->log_file,
$log_entry,
FILE_APPEND | LOCK_EX
);
if ($result === false) {
error_log("无法写入日志文件: {$this->log_file}");
}
return $result !== false;
}
public function error($message) {
return $this->log($message, 'ERROR');
}
public function warning($message) {
return $this->log($message, 'WARNING');
}
public function info($message) {
return $this->log($message, 'INFO');
}
}
// 使用示例
$logger = new Logger('application.log');
$logger->info('应用程序启动');
$logger->error('数据库连接失败');
$logger->warning('磁盘空间不足');
echo "日志记录完成";
?>
示例6:保存用户上传的数据
<?php
function saveUserData($user_id, $data) {
// 验证用户ID
if (!is_numeric($user_id) || $user_id <= 0) {
throw new Exception("无效的用户ID");
}
// 创建用户目录(如果不存在)
$user_dir = "users/{$user_id}";
if (!file_exists($user_dir)) {
if (!mkdir($user_dir, 0755, true)) {
throw new Exception("无法创建用户目录: {$user_dir}");
}
}
// 验证数据
if (empty($data) || !is_array($data)) {
throw new Exception("无效的用户数据");
}
// 添加时间戳
$data['last_updated'] = date('Y-m-d H:i:s');
// 保存为JSON
$json_data = json_encode($data, JSON_PRETTY_PRINT);
$filename = "{$user_dir}/data.json";
// 安全写入(使用文件锁)
$bytes_written = file_put_contents(
$filename,
$json_data,
LOCK_EX
);
if ($bytes_written === false) {
throw new Exception("保存用户数据失败");
}
return [
'filename' => $filename,
'bytes_written' => $bytes_written,
'timestamp' => $data['last_updated']
];
}
// 使用示例
try {
$user_data = [
'name' => 'Alice',
'email' => 'alice@example.com',
'preferences' => [
'theme' => 'dark',
'language' => 'zh-CN'
]
];
$result = saveUserData(123, $user_data);
echo "用户数据已保存到: {$result['filename']}";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
示例7:写入大文件(分块写入)
<?php
function writeLargeFile($filename, $generator, $chunk_size = 1024 * 1024) {
// 分块写入大文件
$temp_file = $filename . '.tmp';
$bytes_total = 0;
// 以追加模式打开临时文件
$fp = fopen($temp_file, 'a');
if (!$fp) {
throw new Exception("无法打开临时文件: {$temp_file}");
}
try {
foreach ($generator as $chunk) {
// 对每个数据块进行写入
$bytes_written = fwrite($fp, $chunk);
if ($bytes_written === false) {
throw new Exception("写入数据块失败");
}
$bytes_total += $bytes_written;
}
fclose($fp);
// 重命名临时文件为最终文件名
if (!rename($temp_file, $filename)) {
throw new Exception("无法重命名文件");
}
return $bytes_total;
} catch (Exception $e) {
// 清理临时文件
fclose($fp);
@unlink($temp_file);
throw $e;
}
}
// 使用示例:生成大文件
function generateLargeData($total_size) {
$remaining = $total_size;
while ($remaining > 0) {
$chunk_size = min(1024 * 1024, $remaining); // 每次最多1MB
yield str_repeat('X', $chunk_size);
$remaining -= $chunk_size;
}
}
try {
$bytes = writeLargeFile('large_file.txt', generateLargeData(10 * 1024 * 1024));
echo "成功写入 {$bytes} 字节的大文件";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>
与类似函数的比较
| 函数 |
描述 |
优点 |
缺点 |
适用场景 |
file_put_contents() |
将字符串写入文件 |
简单易用,一次函数调用完成所有操作 |
大文件可能内存消耗大 |
小文件写入、配置保存、日志记录 |
fwrite() |
写入文件 |
可控制写入大小,适合大文件 |
需要手动打开关闭文件 |
大文件分块写入、二进制文件 |
fputs() |
写入文件(fwrite的别名) |
与fwrite完全相同 |
需要手动打开关闭文件 |
同fwrite |
fprintf() |
格式化写入文件 |
支持格式化输出 |
需要手动打开关闭文件 |
格式化文本输出 |
file() + implode() |
读取数组后组合写入 |
可处理数组数据 |
效率较低 |
数组数据转换 |
性能优化建议
最佳实践
- 对于小于10MB的数据,
file_put_contents()是合适的
- 对于大文件,使用
fwrite()分块写入
- 并发写入时使用
LOCK_EX标志防止数据损坏
- 日志文件使用
FILE_APPEND标志追加写入
- 确保目标目录有写入权限
- 写入前检查磁盘空间是否充足
- 使用try-catch处理可能出现的异常
常见错误和解决方法
常见问题
- 权限不足: 确保目录有写入权限,检查权限设置
- 磁盘空间不足: 写入前检查磁盘剩余空间
- 路径错误: 使用绝对路径,确保目录存在
- 并发冲突: 使用
LOCK_EX标志确保并发安全
- 内存不足: 大文件使用分块写入方式
- 字符编码问题: 确保数据编码与文件编码一致
完整示例:安全的文件写入类
<?php
class SafeFileWriter {
private $default_flags = LOCK_EX;
public function write($filename, $data, $append = false) {
// 检查目录是否存在
$dir = dirname($filename);
if (!file_exists($dir)) {
if (!mkdir($dir, 0755, true)) {
throw new Exception("无法创建目录: {$dir}");
}
}
// 检查磁盘空间
$free_space = disk_free_space($dir);
$data_size = is_string($data) ? strlen($data) : 1024; // 估计大小
if ($free_space !== false && $free_space < $data_size * 2) {
throw new Exception("磁盘空间不足");
}
// 构建标志
$flags = $this->default_flags;
if ($append) {
$flags |= FILE_APPEND;
}
// 写入文件
$bytes_written = file_put_contents($filename, $data, $flags);
if ($bytes_written === false) {
throw new Exception("写入文件失败: {$filename}");
}
return $bytes_written;
}
public function writeJson($filename, $data, $append = false) {
// 将数据编码为JSON
$json_data = json_encode($data, JSON_PRETTY_PRINT);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new Exception("JSON编码错误: " . json_last_error_msg());
}
return $this->write($filename, $json_data, $append);
}
public function writeCsv($filename, $data, $delimiter = ',') {
// 将数据写入CSV格式
if (!is_array($data) || empty($data)) {
throw new Exception("无效的CSV数据");
}
$fp = fopen($filename, 'w');
if (!$fp) {
throw new Exception("无法打开文件: {$filename}");
}
try {
foreach ($data as $row) {
if (fputcsv($fp, $row, $delimiter) === false) {
throw new Exception("写入CSV行失败");
}
}
fclose($fp);
return filesize($filename);
} catch (Exception $e) {
fclose($fp);
throw $e;
}
}
}
// 使用示例
try {
$writer = new SafeFileWriter();
// 写入文本文件
$bytes1 = $writer->write('output/text.txt', "Hello, World!\n");
echo "文本文件写入成功: {$bytes1} 字节
";
// 写入JSON文件
$json_data = ['name' => 'Bob', 'score' => 95];
$bytes2 = $writer->writeJson('output/data.json', $json_data);
echo "JSON文件写入成功: {$bytes2} 字节
";
// 写入CSV文件
$csv_data = [
['Name', 'Age', 'Email'],
['Alice', 30, 'alice@example.com'],
['Bob', 25, 'bob@example.com']
];
$bytes3 = $writer->writeCsv('output/data.csv', $csv_data);
echo "CSV文件写入成功: {$bytes3} 字节";
} catch (Exception $e) {
echo "错误: " . $e->getMessage();
}
?>