如果您想清空檔案內容,請記住,以 w 模式開啟檔案會自動截斷檔案,因此不必這樣做...
<?php
$fp = fopen("/tmp/file.txt", "r+");
ftruncate($fp, 0);
fclose($fp);
?>
您可以直接這樣做...
<?php
$fp = fopen("/tmp/file.txt", "w");
fclose($fp);
?>
(PHP 4, PHP 5, PHP 7, PHP 8)
ftruncate — 將檔案截斷到指定的長度
stream
檔案指標。
注意事項:
stream
必須以寫入模式開啟。
size
要截斷的大小。
注意事項:
如果
size
大於檔案大小,則檔案會以空位元組 (null bytes) 擴充。如果
size
小於檔案大小,則檔案會被截斷到該大小。
範例 #1 檔案截斷範例
<?php
$filename = 'lorem_ipsum.txt';
$handle = fopen($filename, 'r+');
ftruncate($handle, rand(1, filesize($filename)));
rewind($handle);
echo fread($handle, filesize($filename));
fclose($handle);
?>
注意事項:
檔案指標不會改變。
如果您想清空檔案內容,請記住,以 w 模式開啟檔案會自動截斷檔案,因此不必這樣做...
<?php
$fp = fopen("/tmp/file.txt", "r+");
ftruncate($fp, 0);
fclose($fp);
?>
您可以直接這樣做...
<?php
$fp = fopen("/tmp/file.txt", "w");
fclose($fp);
?>
在 ftruncate 後寫入
我沒想到我可以在檔案中間的任何位置寫入。我以為我會寫在檔案的開頭,但前 4 個位元組自動填入了 NULL,後面跟著 "56"
<?php
$str1 = 1234;
$str2 = 56;
$datei = "test.txt";
$dh = fopen($datei,"w");
fwrite($dh, $str1);
fclose($dh);
$dh = fopen ($datei,"r+");
echo "內容: ".fread($dh, filesize($datei))."<br>";
echo "fread 後的指標位置:".ftell($dh)."<br>";
ftruncate($dh, 0);
echo "truncate 後的指標位置:".ftell($dh)."<br>";
fwrite($dh, $str2);
echo "fwrite 後的指標位置:".ftell($dh)."<br>";
rewind($dh);
echo "rewind 後的指標位置:".ftell($dh)."<br>";
$str = fread($dh, 6);
echo "內容: $str<br>ASCII 碼:";
for($i = 0; $i < 6; $i++)
echo ord($str{$i})."-";
fclose($dh);
/*
輸出:
內容: 1234
fread 後的指標位置:4
truncate 後的指標位置:4
fwrite 後的指標位置:6
rewind 後的指標位置:0
內容: 56
ASCII 碼:0-0-0-0-53-54
*/
?>
因此,不僅 ftruncate 會用 NULL 填滿一個空檔案,如前述說明。fread 也會用 NULL 填滿前導空格。
rc at opelgt dot org 提到的問題似乎完全合乎邏輯。
當指標位於偏移量 4 且您截斷檔案時,指標仍位於偏移量 4。
因此,當您執行 write() 時,作業系統會以前 4 個位元組填入空位元組 - PHP 並沒有錯。它填入空位元組是因為磁碟上有資料,需要用零位元清除。
即使這是作業系統的一個陷阱,為了避免資料損毀,PHP 文件應該清楚地提到這一點。此外,如果 PHP 在截斷到較小尺寸後自動將指標的偏移量設定為 SEEK_END 以防止出錯,那就太好了。
如果您想使用 ftruncate 但保留檔案結尾
<?php
function ftruncatestart($filename,$maxfilesize){
$size=filesize($filename);
if ($size<$maxfilesize*1.0) return;
$maxfilesize=$maxfilesize*0.5; //我們不想太頻繁地執行這個動作...
$fh=fopen($filename,"r+");
$start=ftell($fh);
fseek($fh,-$maxfilesize,SEEK_END);
$drop=fgets($fh);
$offset=ftell($fh);
for ($x=0;$x<$maxfilesize;$x++){
fseek($fh,$x+$offset);
$c=fgetc($fh);
fseek($fh,$x);
fwrite($fh,$c);
}
ftruncate($fh,$maxfilesize-strlen($drop));
fclose($fh);
}
?>
它不會直接截斷,而是搜尋換行符號,這樣可以避免損壞您的 csv 或日誌檔。 但我不知道這是否會加重您硬碟讀寫頭的負擔 ;)。