PHP Conference Japan 2024

fwrite

(PHP 4, PHP 5, PHP 7, PHP 8)

fwrite二進位安全檔案寫入

說明

fwrite(資源 $stream, 字串 $data, ?整數 $length = null): 整數|false

fwrite()data 的內容寫入到 stream 指向的檔案串流中。

參數

stream

一個檔案系統指標 資源,通常使用 fopen() 建立。

data

要寫入的字串。

length

如果 length 是一個 整數,寫入將在寫入 length 個位元組後停止,或者在到達 data 的結尾時停止,以先發生的為準。

返回值

fwrite() 返回寫入的位元組數,如果失敗則返回 false

錯誤/異常

fwrite() 在失敗時會引發 E_WARNING

更新日誌

版本 說明
8.0.0 length 現在可以為 null。

範例

範例 #1 一個簡單的 fwrite() 範例

<?php
$filename
= 'test.txt';
$somecontent = "Add this to the file\n";

// 首先確保檔案存在且可寫入。
if (is_writable($filename)) {

// 在我們的範例中,我們以附加模式開啟 $filename。
// 檔案指標位於檔案底部,因此
// 當我們 fwrite() 它時,$somecontent 將會寫入到那裡。
if (!$fp = fopen($filename, 'a')) {
echo
"無法開啟檔案 ($filename)";
exit;
}

// 將 $somecontent 寫入到我們開啟的檔案中。
if (fwrite($fp, $somecontent) === FALSE) {
echo
"無法寫入檔案 ($filename)";
exit;
}

echo
"成功,已將 ($somecontent) 寫入檔案 ($filename)";

fclose($fp);

} else {
echo
"檔案 $filename 不可寫入";
}
?>

注意事項

注意:

寫入網路串流可能會在寫入整個字串之前結束。可以檢查 fwrite() 的返回值。

<?php
function fwrite_stream($fp, $string) {
for (
$written = 0; $written < strlen($string); $written += $fwrite) {
$fwrite = fwrite($fp, substr($string, $written));
if (
$fwrite === false) {
return
$written;
}
}
return
$written;
}
?>

注意:

在區分二進位檔案和文字檔案的系統上(例如 Windows),必須在 fopen() 模式參數中包含 'b' 來開啟檔案。

注意:

如果 stream 是以附加模式使用 fopen() 開啟的,則 fwrite() 是原子性的(除非在某些平台上,data 的大小超過檔案系統的區塊大小,且檔案位於本機檔案系統上)。也就是說,在呼叫 fwrite() 之前不需要使用 flock() 鎖定資源;所有資料都會不間斷地寫入。

注意:

如果對檔案指標寫入兩次,則資料將會附加到檔案內容的末尾。

<?php
$fp
= fopen('data.txt', 'w');
fwrite($fp, '1');
fwrite($fp, '23');
fclose($fp);

// 'data.txt' 的內容現在是 123,而不是 23!
?>

另請參閱

新增註解

使用者貢獻的註解 10 則註解

nate at frickenate dot com
14 年前
我在使用 fwrite() 時遇到問題,在預期應回傳 false 的情況下,它卻回傳 0,因此我查看了 PHP fwrite() 的原始碼。該函式只有在傳入無效參數時才會回傳 false。任何其他錯誤,例如管道破裂或連線關閉,都會導致回傳值小於 strlen($string),大多數情況下為 0。

因此,如果使用迴圈重複呼叫 fwrite(),直到寫入的位元組總數等於完整值的 strlen(),或者期望在錯誤時回傳 false,那麼如果連線斷開,就會導致無限迴圈。

這表示文件中 fwrite_stream() 程式碼的範例,以及其他人在評論中發布的所有「輔助」函式都是有問題的。您*必須*檢查回傳值是否為 0,並立即中止或追蹤最大重試次數。

以下是文件中的範例。這段程式碼是*有問題的*,因為管道破裂會導致 fwrite() 以回傳值 0 無限迴圈。由於迴圈僅在 fwrite() 回傳 false 或成功寫入所有位元組時才會中斷,因此在失敗時會發生無限迴圈。

<?php
// 有問題的函式 - 當 fwrite() 回傳 0 時會無限迴圈
function fwrite_stream($fp, $string) {
for (
$written = 0; $written < strlen($string); $written += $fwrite) {
$fwrite = fwrite($fp, substr($string, $written));
if (
$fwrite === false) {
return
$written;
}
}
return
$written;
}
?>
divinity76 at gmail dot com
3 年前
如果您需要一個能寫入所有資料的函式,或許可以試試

<?php

/**
* 寫入所有資料,否則拋出例外
*
* @param mixed $handle
* @param string $data
* @throws \RuntimeException 當 fwrite 返回值 < 1 但仍有更多資料要寫入時
* @return void
*/
/*private static*/
function fwrite_all($handle, string $data): void
{
$original_len = strlen($data);
if (
$original_len > 0) {
$len = $original_len;
$written_total = 0;
for (;;) {
$written_now = fwrite($handle, $data);
if (
$written_now === $len) {
return;
}
if (
$written_now < 1) {
throw new
\RuntimeException("只能寫入 {$written_total}/{$original_len} 位元組!");
}
$written_total += $written_now;
$data = substr($data, $written_now);
$len -= $written_now;
// assert($len > 0);
// assert($len === strlen($data));
}
}
}
niklesh at example dot com
4 年前
$handles 也可以用於在控制台中輸出,如下例所示

fwrite(STDOUT, "控制台輸出");
Chris Blown
21 年前
別忘了檢查 fwrite 的返回值是否有錯誤!即使您成功開啟了一個檔案以進行寫入,也不一定表示您可以寫入它。

在某些系統上,如果檔案系統已滿,可能會發生這種情況,您仍然可以開啟檔案並建立檔案系統 inode,但 fwrite 將會失敗,導致產生一個零位元組的檔案。
匿名
8 年前
// 您想要複製虛擬檔案或傳送虛擬檔案
// 可以傳送大於 4GB 的檔案,並且在不使用 FSEEK 的情況下寫入,其限制為 PHP_INT_MAX。它適用於 32 位元或 64 位元的系統
// fwrite 和 fread 沒有指標位置限制

<?php

$gfz
= filesize_dir("d:\\starwars.mkv"); // 11.5GB
echo 'Z:',$gfz,PHP_EOL;

$fz = fopen('d:\\test2.mkv', 'wb');
$fp = fopen('d:\\starwars.mkv', 'rb');
echo
PHP_EOL;
$a = (float) 0;
while((
$l=fread($fp, 65536))) {
fwrite($fz, $l);
if((
$a+=65536)%5) echo "\r", '>', $a, ' : ' , $gfz;
}

fclose($fp);
fclose($fz);

// test2.mkv 大小為 11.5GB

function filesize_dir($file) {
exec('dir ' . $file, $inf);
$size_raw = $inf[6];
$size_exp = explode(" ",$size_raw);
$size_ext = $size_exp[19];
$size_int = (float) str_replace(chr(255), '', $size_ext);
return
$size_int;
}
?>
dharris dot nospam at removethispart dot drh dot net
16 年前
有些人說,寫入 socket 時,可能不會寫入所有要求寫入的位元組。您可能需要再次呼叫 fwrite 來寫入第一次未寫入的位元組。(至少 UNIX 中的 write() 系統呼叫是這樣運作的。)

這是有用的程式碼(警告:未經多位元組字元集測試)

function fwrite_with_retry($sock, &$data)
{
$bytes_to_write = strlen($data);
$bytes_written = 0;

while ( $bytes_written < $bytes_to_write )
{
if ( $bytes_written == 0 ) {
$rv = fwrite($sock, $data);
} else {
$rv = fwrite($sock, substr($data, $bytes_written));
}

if ( $rv === false || $rv == 0 )
return( $bytes_written == 0 ? false : $bytes_written );

$bytes_written += $rv;
}

return $bytes_written;
}

像這樣呼叫它

$rv = fwrite_with_retry($sock, $request_string);

if ( ! $rv )
die("無法將 request_string 寫入 socket");
如果 ( $rv != strlen($request_string) )
die("寫入請求字串到 socket 時排序錯誤");
synnus at gmail dot com
8 年前
// 您想要複製虛擬檔案或傳送虛擬檔案
// 可以傳送大於 4GB 的檔案,並且在不使用 FSEEK 的情況下寫入,其限制為 PHP_INT_MAX。它適用於 32 位元或 64 位元的系統
// fwrite 和 fread 沒有指標位置限制

<?php

$gfz
= filesize_dir("d:\\starwars.mkv"); // 11.5GB
echo 'Z:',$gfz,PHP_EOL;

$fz = fopen('d:\\test2.mkv', 'wb');
$fp = fopen('d:\\starwars.mkv', 'rb');
echo
PHP_EOL;
$a = (float) 0;
while((
$l=fread($fp, 65536))) {
fwrite($fz, $l);
if((
$a+=65536)%5) echo "\r", '>', $a, ' : ' , $gfz;
}

fclose($fp);
fclose($fz);

// test2.mkv 大小為 11.5GB

function filesize_dir($file) {
exec('dir ' . $file, $inf);
$size_raw = $inf[6];
$size_exp = explode(" ",$size_raw);
$size_ext = $size_exp[19];
$size_int = (float) str_replace(chr(255), '', $size_ext);
return
$size_int;
}
?>
php at biggerthanthebeatles dot com
21 年前
希望這能幫助其他新手。

如果您正在將數據寫入 Windows 系統上的 txt 文件並且需要換行,請使用 \r\n 。這將寫入十六進制的 OD OA。

例如:
$batch_data= "一些數據... \r\n";
fwrite($fbatch,$batch_data);

這相當於在記事本中打開一個 txt 文件,在行尾按下 Enter 鍵並保存它。
匿名
15 年前
如果您在文件的中间写入数据,它会覆盖那里的内容,而不是将文件的其余部分向后移动。
chedong at hotmail dot com
21 年前
如果未提供長度參數,fwrite 輸出會去除反斜線,例如

<?php
$str
= "c:\\01.txt";
$out = fopen("out.txt", "w");
fwrite($out, $str);
fclose($out);
?>

out.txt 將會是
c:^@1.txt
未跳脫的 '\\0' 將會變成 '\0' ==> 0x00。

正確的寫法是將 fwrite 改成
fwrite($out, $str, strlen($str));
To Top