傳統 file_get_contents + fwrite 需將整個檔案讀入記憶體再寫出,大檔案易造成記憶體飆升。PHP 的 stream_copy_to_stream() 直接在內核層面將資料從來源串流搬移到目標串流,實現「零拷貝」,極大降低記憶體佔用與 CPU 開銷,是大檔案、網路串流傳輸的首選。
<?php
/**
* 使用串流複製檔案
* @return int|false 成功回傳複製位元組數,失敗回傳 false
*/
function streamCopy(string $source, string $dest): int|false
{
// 以二進位模式開啟來源(讀取)與目標(寫入)
$src = @fopen($source, 'rb');
$dst = @fopen($dest, 'wb');
if (!$src || !$dst) {
if ($src) fclose($src);
if ($dst) fclose($dst);
return false;
}
// 核心:直接在串流間複製
$bytes = stream_copy_to_stream($src, $dst);
fclose($src);
fclose($dst);
return $bytes;
}
// 範例:複製 1GB 影片檔,記憶體佔用極低
$copied = streamCopy('/data/video.mp4', '/backup/video.mp4');
if ($copied !== false) {
echo "複製完成,共 $copied 位元組";
} else {
echo "複製失敗";
}
?>
<?php
// 僅複製前 10MB
$bytes = stream_copy_to_stream($src, $dst, 10 * 1024 * 1024);
// 從來源位移 100MB 開始複製(需來源可定位)
fseek($src, 100 * 1024 * 1024);
$bytes = stream_copy_to_stream($src, $dst);
?>
| 方法 | 記憶體佔用 | 適用場景 | 備註 |
|---|---|---|---|
copy() | 低(內核優化) | 本地檔案快速複製 | 最簡單,支援 URL 封裝協議 |
file_get_contents + fwrite | 高(全檔載入記憶體) | 小檔、需修改內容再寫入 | 大檔危險 |
fread/fwrite 迴圈 | 低(緩衝區大小) | 需自定義邏輯(加密、壓縮、進度條) | 手動控制最靈活 |
| stream_copy_to_stream | 極低(零拷貝) | 大檔、網路串流、管道轉發 | 效能最佳,無法中途處理資料 |
<?php
$url = 'https://example.com/large-dataset.zip';
$localFile = '/tmp/dataset.zip';
$src = @fopen($url, 'rb'); // 需開啟 allow_url_fopen
$dst = @fopen($localFile, 'wb');
if ($src && $dst) {
$bytes = stream_copy_to_stream($src, $dst);
fclose($src);
fclose($dst);
echo "下載完成:$bytes 位元組";
} else {
echo "開啟串流失敗";
}
?>
fseek 指定位移。int 複製位元組數,失敗回傳 false(注意 0 也可能表示空檔案成功)。stream_copy_to_stream($src, $dst, maxlen: 1024*1024) 命名參數。掌握 stream_copy_to_stream,讓你的 PHP 腳本輕鬆應對 GB 級檔案搬移、即時串流轉發等高併發 I/O 場景。