3

I end up having my script appending the new changes that I wanted to make to the end of the file instead of in the actual file.

open (INCONFIG, "+<$text") or die $!;
@config = <INCONFIG>;
foreach(@config)
{
    if ( $_ =~ m/$checker/ )
    {
        $_ = $somethingnew;
    }
print INCONFIG $_;
}
close INCONFIG or die;

Ultimately I wanted to rewrite the whole text again, but with certain strings modified if it matched the search criterion. But so far it only appends ANOTHER COPY of the entire file(with changes) to the bottom of the old file.

I know that I can just close the file, and use another write file -handle and parse it in. But was hoping to be able to learn what I did wrong, and how to fix it.

tshepang
  • 12,111
  • 21
  • 91
  • 136
user1539348
  • 513
  • 1
  • 7
  • 20
  • From the [official Perl FAQ](http://faq.perl.org): [How do I change, delete, or insert a line in a file, or append to the beginning of a file?](http://learn.perl.org/faq/perlfaq5.html#How-do-I-change-delete-or-insert-a-line-in-a-file-or-append-to-the-beginning-of-a-file-) ||| http://stackoverflow.com/q/2322140 – daxim Jul 23 '12 at 08:16

4 Answers4

1

As I understand open, using read/write access for a text file isn't a good idea. After all a file just is a byte stream: Updating a part of the file with something of a different length is the stuff headaches are made of ;-)

Here is my approach: Try to emulate the -i "inplace" switch of perl. So essentially we write to a backup file, which we will later rename. (On *nix system, there is some magic with open filehandles keeping deleted files available, so we don't have to create a new file. Lets do it anyway.)

my $filename = ...;
my $tempfile = "$filename.tmp";
open my $inFile,  '<', $filename or die $!;
open my $outFile, '>', $tempfile or die $!;

while (my $line = <$inFile>) {
    $line = doWeirdSubstitutions($line);
    print $outFile $line;
}

close $inFile  or die $!;
close $outFile or die $!;

rename $tempfile, $filename
  or die "rename failed: $!"; # will break under weird circumstances.

# delete temp file
unlink $tempfile or die $!;

Untested, but obvious code. Does this help with your problem?

amon
  • 57,091
  • 2
  • 89
  • 149
0

Your problem is a misunderstanding of what <+ "open for update" does. It is discussed in the Perl Tutorial at Mixing Reads and Writes.

What you really want to do is copy the old file to a new file and then rename it after the fact. This is discussed in the perlfaq5 mentioned by daxim. Plus there are entire modules dedicated to doing this safely, such as File::AtomicWrite. These help with the issue of your program aborting and leaving you with a clobbered file.

Bill Ruppert
  • 8,956
  • 7
  • 27
  • 44
0

As others pointed out, there are better ways :)

But if you really want to read and write using +<, you should remember that, after reading the file, you're at the end of the file... That explains that your output is appended after the original content.

What you need to do is reset the file-pointer to the beginning of the file, using seek:

seek(INCONFIG ,0,0);

Then start writing...

pavel
  • 3,488
  • 1
  • 20
  • 20
0

perlopentut says this about mixing reads and writes

In fact, when it comes to updating a file, unless you're working on a binary file as in the WTMP case above, you probably don't want to use this approach for updating. Instead, Perl's -i flag comes to the rescue.

Another way is to use the Tie::File module. The code reduces to just this:

tie my @config, 'Tie::File', $text or die $!;

s/$checker/$somethingnew/g for @config;

But remember to back the file up before you modify it until you have debugged your program.

Borodin
  • 126,100
  • 9
  • 70
  • 144