-2

I am trying to modify a config file.

I first read it into @buffer, depending on a regex match. The modified buffer gets written back on disk, in case the file got smaller, a trunciation is done.

Unfortunatly this does not work, and it already crashes at fseek, but as far as I can say my usage of fseek conforms to perl doc.

open (my $file, "+<", "somefilethatexists.txt");
flock ($file, LOCK_EX);
foreach my $line (<$file>) {
    if ($line =~ m/(something)*/) {
        push (@buffer, $line);
    }
}
print "A\n";
seek($file,0,0); #seek to the beginning, we read some data already

print "B\n"; # never appears

write($file, join('\n',@buffer)); #write new data
truncate($file, tell($file)); #get rid of everything beyond the just written data
flock($file, LOCK_UN);
close ($file);
drahnr
  • 6,782
  • 5
  • 48
  • 75
  • 2
    Where does fseek come from? It doesn't seem to be one of perls core functions. Did you try using seek instead? What is the nature of the "crash"? Is it a core dump or does perl die with an error message? – tauli Aug 17 '12 at 10:02
  • [`write()`](http://perldoc.perl.org/functions/write.html "perldoc -f write") doesn't do what you think it does. You probably want to use [`print()`](http://perldoc.perl.org/functions/print.html "perldoc -f print"). – Brad Gilbert Oct 12 '12 at 21:28
  • `write($file, join('\n',@buffer));` should be `print {$file} join("\n",@buffer));` – Brad Gilbert Oct 12 '12 at 21:31

3 Answers3

3

perlopentut says this about Mixing Reads and Writes

... when it comes to updating a file ... you probably don't want to use this approach for updating.

You should use Tie::File for this. It opens the file for both read and write on the same filehandle and allows you to treat a file as an array of lines

use strict;
use warnings;

use Tie::File;

tie my @file, 'Tie::File', 'somefilethatexists.txt' or die $!;

for (my $i = 0; $i < @file; ) {
  if (m/(something)*/) {
    $i++;
  }
  else {
    splice @file, $i, 1;
  }
}

untie @file;
Borodin
  • 126,100
  • 9
  • 70
  • 144
1

Maybe you can try this:

$^I = '.bak';
@ARGV = 'somefilethatexists.txt';
while (<>) {
    if (/(something)*/) {
        print;
    }
}
cdtits
  • 1,118
  • 6
  • 7
  • I'd rather understand why fseek fails, also I need to lock the file via flock. – drahnr Aug 17 '12 at 09:58
  • @drahnr:You can put a + in front of the > or < to indicate that you want both read and write access to the file; thus +< is almost always preferred for read/write updates--the +> mode would clobber the file first. You can't usually use either read-write mode for updating textfiles, since they have variable-length records. – cdtits Aug 17 '12 at 10:11
1

Where are your fseek(), fwrite() and ftruncate() functions defined? Perl doesn't have those functions. You should be using seek(), print() (or syswrite()) and truncate(). We can't really help you if you're using functions that we know nothing about.

You also don't need (and probably don't want) that explicit call to unlock the file or the call to close the file. The filehandle will be closed and unlocked as soon as your $file variable goes out of scope.

Dave Cross
  • 68,119
  • 3
  • 51
  • 97