18.17. Modifying a File in Place Without a Temporary File
18.17.1. Problem
You want to change a file without using
a temporary file to hold the changes.
18.17.2. Solution
Read the file into memory, make the changes, and rewrite the file.
Open the file with mode r+
(rb+, if necessary, on Windows) and adjust its
length with ftruncate(
)
after writing out changes:
// open the file for reading and writing
$fh = fopen('pickles.txt','r+') or die($php_errormsg);
// read the entire file into $s
$s = fread($fh,filesize('pickles.txt')) or die($php_errormsg);
// ... modify $s ...
// seek back to the beginning of the file and write the new $s
rewind($fh);
if (-1 == fwrite($fh,$s)) { die($php_errormsg); }
// adjust the file's length to just what's been written
ftruncate($fh,ftell($fh)) or die($php_errormsg);
// close the file
fclose($fh) or die($php_errormsg);
18.17.3. Discussion
The following code turns text emphasized with asterisks or slashes
into text with
HTML
<b> or <i> tags:
$fh = fopen('message.txt','r+') or die($php_errormsg);
// read the entire file into $s
$s = fread($fh,filesize('message.txt')) or die($php_errormsg);
// convert *word* to <b>word</b>
$s = preg_replace('@\*(.*?)\*@i','<b>$1</b>',$s);
// convert /word/ to <i>word</i>
$s = preg_replace('@/(.*?)/@i','<i>$1</i>',$s);
rewind($fh);
if (-1 == fwrite($fh,$s)) { die($php_errormsg); }
ftruncate($fh,ftell($fh)) or die($php_errormsg);
fclose($fh) or die($php_errormsg);
Because adding HTML tags makes the file grow, the entire file has to
be read into memory and then processed. If the changes to a file make
each line shrink (or stay the same size), the file can be processed
line by line, saving memory. This example converts text marked with
<b> and <i> to text
marked with asterisks and slashes:
$fh = fopen('message.txt','r+') or die($php_errormsg);
// figure out how many bytes to read
$bytes_to_read = filesize('message.txt');
// initialize variables that hold file positions
$next_read = $last_write = 0;
// keep going while there are still bytes to read
while ($next_read < $bytes_to_read) {
/* move to the position of the next read, read a line, and save
* the position of the next read */
fseek($fh,$next_read);
$s = fgets($fh,1048576) or die($php_errormsg);
$next_read = ftell($fh);
// convert <b>word</b> to *word*
$s = preg_replace('@<b[^>]*>(.*?)</b>@i','*$1*',$s);
// convert <i>word</i> to /word/
$s = preg_replace('@<i[^>]*>(.*?)</i>@i','/$1/',$s);
/* move to the position where the last write ended, write the
* converted line, and save the position for the next write */
fseek($fh,$last_write);
if (-1 == fwrite($fh,$s)) { die($php_errormsg); }
$last_write = ftell($fh);
}
// truncate the file length to what we've already written
ftruncate($fh,$last_write) or die($php_errormsg);
// close the file
fclose($fh) or die($php_errormsg);
 |  |  | | 18.16. Removing the Last Line of a File |  | 18.18. Flushing Output to a File |
Copyright © 2003 O'Reilly & Associates. All rights reserved.
|
|