in reply to Capture Contents AND Overwrite without Opening Twice?

Hey All, thanks for the new replies...

Sorry, but I am soo confused right now... Maybe it's because I'm at the end of my day, but I am just not grasping how this is supposed
to work? The one example that was given by roboticus, to me, almost seems like its written in reverse. I'm sure it's not because I know
you guys are the experts, but I guess I'm just totally lost here...

From what I read (*at perldoc.perl.org), it sounds like you can use 'seek' to move around the File, but in bytes or characters and not
lines (right?). Something like, you pass it a number as the second argument to seek, positive num to move forward x bytes or
negative to move in reverse -x bytes.

And then truncate can be used to truncate or remove portions of a file to a specific length. I also read about 'tell' which will tell you
where in the file you are currently reading from, correct (*not sure if I need that or not..)?


If possible, could someone explain (*in psudeo-code) how exactly it SHOULD work...? Something like:
(*use open() here) - Open the filehandle FH (*use array and FH) - Slurp all lines from FH to Array (*use seek here) - Go to a position in the file (*etc....)
I'm just not grasping the logic behind it I guess...

Or maybe an example. Let's say I have the File "test_file.log" containing:
COL-1 COL-2 COL-3 COL-4 Line #1 Line #2 Line #3 Line #4 Line #5
And basically, that log file should never have more then 6 TOTAL lines (*5 lines containing the data, and +1 for the Col headings), and the
newest data would be at the bottom.

And if I ran my script and added a NEW line of data to the file, the end result should be:
COL-1 COL-2 COL-3 COL-4 Line #2 Line #3 Line #4 Line #5 Line #6
I don't know if that example changes any of your understanding's of my original post, sorry if I'm being a pain... I'm just trying to grasp how
exactly seek and truncate can be used together on this...? I'm going to be heading home in a minute or 2 so maybe I'll understand better tomorrow when my head is a bit fresher...

Again, sorry for the confusion on my part, it's been a long day..!
And thanks AGAIN EVERYBODY for the replies, it is VERY much appreciated!

Thanks,
Matt

Replies are listed 'Best First'.
Re^2: Capture Contents AND Overwrite without Opening Twice?
by Anonymous Monk on Oct 08, 2014 at 22:38 UTC

    roboticus's example is a script that reverses itself (it opens $0), and it was run first, then printed, so it came out in reverse :-)

    seek works in bytes, not characters or lines. You understood correctly that you can use it to move the current position around in the file (relative to its beginning, the current position, or its end). truncate cuts down the file to a certain size (AFAIK also in bytes, definitely not lines), but always from the beginning of the file.

    I understand you want to preserve the first line of the file. You could do that by figuring out where that line ends (in bytes!), and truncate the file to there. However, since we're only talking about one line here, the logic would be much easier if you just clobber the entire file, modify the array of lines, and write everything back out.

    my $MAXLINES=20; # not including header open my $fh, '+<', 'foo.txt' or die $!; my @lines = <$fh>; splice @lines, 1, @lines-$MAXLINES if @lines>$MAXLINES; push @lines, "newline\n"; truncate $fh, 0 or die "truncate failed"; seek $fh, 0, 0 or die "seek failed"; print $fh @lines; close $fh;

    But I would also second dasgar's suggestion for Tie::File.

    use Tie::File; my $MAXLINES=20; # not including header tie my @lines, 'Tie::File', 'foo.txt' or die "tie failed"; splice @lines, 1, @lines-$MAXLINES if @lines>$MAXLINES; push @lines, "newline\n"; untie @lines;
Re^2: Capture Contents AND Overwrite without Opening Twice?
by Laurent_R (Canon) on Oct 08, 2014 at 22:34 UTC
    Well you could use the -i flag on the command line to modify a file, well at least in a one-liner.

    Otherwise, I would not recommend opening files in read-and-write mode. But if you do want to do it this way, then you need to read the full file first and save the content in an array, make whatever changes you need to the array, and then only write back the array to the file. It works, but that would not be my recommended course of actions.

    I would suggest reading the input file (read mode), writing to a copy of it (write mode), and then, if everything went OK, to do the house cleaning, i.e. deleting the old file (or archiving it under another name), and renaming the new one to what you need.

      This is an important consideration iff the file will be accessed by other processes during the run of the script, or if it's important that the file doesn't get corrupted by either the script dieing or getting shot down externally while it is modifying the file. (probably what MidLifeXis's comment was aimed at as well)