file() 與 file_get_contents() 深度對比兩者都能讀取文件內容,但**返回類型、內存佔用、適用場景**截然不同。選錯函數易導致大文件內存溢出 (OOM) 或多餘處理代碼。
| 特性 | file() | file_get_contents() |
|---|---|---|
| 返回值 | 數組,每行元素含換行符 | 字符串,整個文件內容 |
| 內存佔用 | 略高 (數組結構開銷 + 每行字符串) | 較低 (單一字符串) |
| 換行符處理 | **保留** 行尾 `\n`/`\r\n` (需手動 trim) | 原樣保留所有內容 |
| 大文件風險 | ⚠️ 高 (一次性載入所有行到內存) | ⚠️ 高 (一次性載入整個文件) |
| 流式讀取支持 | ❌ 不支持 | ❌ 不支持 (需用 fopen+fgets) |
| URL 支持 | ✅ 支持 (需 allow_url_fopen=On) | ✅ 支持 |
| 典型用途 | 逐行處理:日誌分析、CSV 解析、配置文件 | 整體處理:模板渲染、JSON 讀取、二進制文件 |
<?php
$file = 'data.txt'; // 內容: "第一行\n第二行\n第三行"
// --- file() ---
$lines = file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
// 結果: ['第一行', '第二行', '第三行']
// 適合直接 foreach 處理每行
foreach ($lines as $lineNum => $line) {
// 處理單行...
}
// --- file_get_contents() ---
$content = file_get_contents($file);
// 結果: "第一行\n第二行\n第三行"
// 需自行分割: $lines = explode("\n", $content);
// 適合直接輸出、json_decode、正則匹配全文
$json = file_get_contents('config.json');
$config = json_decode($json, true);
?>
// 環境: PHP 8.1, SSD, 內存 4G
// file(): 耗時 ~1.2s, 峰值內存 ~280MB (數組開銷大)
// file_get_contents(): 耗時 ~0.8s, 峰值內存 ~120MB (字符串更緊湊)
// 結論: 讀取大文件整體內容,file_get_contents() 更快更省內存。
**無論用哪個,大文件 (>可用內存/2) 都會 OOM**。必須用流式讀取:
<?php
/**
* 逐行讀取大文件生成器,內存常數級
*/
function readLines(string $filename): Generator {
$handle = fopen($filename, 'r');
if (!$handle) throw new Exception("無法打開: $filename");
try {
while (($line = fgets($handle)) !== false) {
yield rtrim($line, "\r\n"); // 去換行符
}
} finally {
fclose($handle);
}
}
// 使用:內存穩定 ~2MB 處理 10GB 日誌
foreach (readLines('/var/log/nginx/access.log') as $line) {
if (strpos($line, ' 500 ') !== false) {
// 處理錯誤行...
}
}
?>
file() 返回行**包含換行符**,直接比較/入庫會帶入 `\n` → **務必用 `FILE_IGNORE_NEW_LINES` 旗標**。file_get_contents()` 讀取二進制文件 (圖片/PDF) 安全,file()` 會嘗試按行分割二進制數據導致錯誤結果。stream_context_create(['http'=>['timeout'=>10]]) 防止掛死。fgetcsv() 處理引號、轉義、換行符嵌入。file($path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)。file_get_contents($path)。fopen + fgets / fread + Generator 流式處理。