PHPfile_put_contents()函数

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(); } ?>