Recipe 7.15 Modifying a File in Place with a Temporary File

7.15.1 Problem

You need to update a file in place, and you can use a temporary file.

7.15.2 Solution

Read from the original file, write changes to a temporary file, and then rename the temporary back to the original:

open(OLD, "<", $old)        or die "can't open $old: $!";
open(NEW, ">", $new)        or die "can't open $new: $!";
while (<OLD>) {
    # change $_, then...
    print NEW $_            or die "can't write $new: $!";
close(OLD)                  or die "can't close $old: $!";
close(NEW)                  or die "can't close $new: $!";
rename($old, "$old.orig")   or die "can't rename $old to $old.orig: $!";
rename($new, $old)          or die "can't rename $new to $old: $!";

This is the best way to update a file "in place."

7.15.3 Discussion

This technique uses little memory compared to the approach that doesn't use a temporary file. It has the added advantages of giving you a backup file and being easier and safer to program.

You can make the same changes to the file using this technique that you can with the version that uses no temporary file. For instance, to insert lines at line 20, say:

while (<OLD>) {
    if ($. =  = 20) {
        print NEW "Extra line 1\n";
        print NEW "Extra line 2\n";
    print NEW $_;

To delete lines 20 through 30, say:

while (<OLD>) {
    next if 20 .. 30;
    print NEW $_;

Note that rename won't work across filesystems, so you should create your temporary file in the same directory as the file being modified.

The truly paranoid programmer would lock the file during the update. The tricky part is that you have to open the file for writing without destroying its contents before you can get a lock to modify it. Recipe 7.18 shows how to do this.

7.15.4 See Also

Recipe 7.1; Recipe 7.16; Recipe 7.17; Recipe 7.18