Re: Help in read and write to file at a same time in same file.
by anonymized user 468275 (Curate) on Apr 04, 2011 at 11:45 UTC
|
There are methods for writing to a file you are reading, but it is much simpler to write to a temporary file and move it over the original when done, e.g.:
my $file = 'fred.txt';
my $tmp = 'fred.txt.tmp' . $$; # habitually I make tmp files unique in
+ case of multiuser usage.
open my $ih, $file;
open my $oh, ">$tmp";
while ( <$ih> ) {
/My_Name/ and $_ = '## ' . $_ . "\n" ; # although a carriage retur
+n is already present
print $oh $_;
}
close $ih;
close $oh;
rename ( $tmp, $file );
| [reply] [d/l] |
Re: Help in read and write to file at a same time in same file.
by cdarke (Prior) on Apr 04, 2011 at 12:00 UTC
|
With text files you can only get this to work if the new lines are exactly the same length as the old ones. Text files are just strings of text interspaced with new-lines (on UNIX). Say you see a file in an editor that looks like this: This is a line
This is another line
and so is this
In reality it looks like this (try od -xc if you are in UNIX):This is a line\nThis is another line\nand so is this\n
Adding a # to the second line, and then rewriting it, would give us this (look carefully):This is a line\n#This is another line\nnd so is this\n
Adding an extra character makes the line longer, so it overwrites the first character of the next line!
Write the output lines to a different file instead then, assuming it worked, rename the new file to the same name as the old one. | [reply] [d/l] [select] |
Re: Help in read and write to file at a same time in same file.
by bart (Canon) on Apr 04, 2011 at 12:38 UTC
|
I want to read and write in file at a time (Is it possible ?)
Yes it is possible (check out "+<" and "+>>" file modes for open) but in your case it's a terrible idea.
Why? Because your output is longer than your input. As a result, you will be overwriting the data before you got a chance to read it.
-i emulates rewriting a file, but actually it's writing to a new file, and the new file replaces the old file when it's finished. On Linux you can notice the difference because the file permissions and/or ownership may end up different from what you started from.
| [reply] |
Re: Help in read and write to file at a same time in same file.
by jpl (Monk) on Apr 04, 2011 at 12:09 UTC
|
Worth contemplating (monks should be contemplative)
before it happens, are the consequences of rerunning the command, or having the machine crash in the middle of a run. If you plan to run it many times, note that you are adding a couple extra ## characters to the line each time you run. Perhaps you want to defend against that.
If something interrupts a run, what happens if you rerun the command? A downside of the i perlrun flag is that it backs up before the run and overwrites the file with the original name. If you crash, you can restore the file to something sane from the backup copy. But if you fail to do so before another run, you'll use the partially complete original file, and destroy the valid backup. I prefer to preserve the original until everything is complete, then rename to update it as atomically as possible. But always check the results of opening and closing the temporary file, and don't do the rename if there was any problem.
| [reply] [d/l] [select] |
Re: Help in read and write to file at a same time in same file.
by educated_foo (Vicar) on Apr 04, 2011 at 11:41 UTC
|
Try perlrun, particularly the -i and -p options. | [reply] |
|
|
And perlvar for $^I, specially when used with @ARGV and <>
| [reply] [d/l] [select] |
Re: Help in read and write to file at a same time in same file.
by Anonymous Monk on Apr 04, 2011 at 11:09 UTC
|
| [reply] |
Re: Help in read and write to file at a same time in same file.
by locked_user sundialsvc4 (Abbot) on Apr 04, 2011 at 17:19 UTC
|
Let me weigh-in on the side of the group of experienced Monks who likewise advocate the following:
-
Read from one file, write to a temporary file . (Consider placing this file in the same location, but with an obviously-different and obviously-temporary filename, e.g. adding an extension to the filename.) Silently delete any copy that now exists.
-
Rename the existing file ... add a different extension.
-
Rename the file built in step #1 into place.
-
Delete (or archive) the existing-file from step #2.
The advantage of this procedure (which should be very well-documented) is that it will easily survive a crash and it can easily be recovered-from in the event of a crash. (In fact, the program could do it automatically when it is re-run.)
“Ka-ka occurs,” and disk-space is plentiful and cheap.
| |
|
|
Perhaps this could be accomplished with yet another perlrun option, maybe -b (for backup). In conjunction with -i (whose behavior it would modify), we could demand that both have non-empty extensions, and further, that no two of the three names reference the same file, thereby defending against foot-shooting behavior like
-i* or -b./* (for which silently
deleting the "copy" might delete the original). It would then be safe to do largely as specified, after step 0, making a copy of the original in the -b extension.
This keeps a backup of the original after the dust settles, much as -i
does now, but also preserves the original, which won't be replaced by the -i version until it has been
completely processed and closed.
| [reply] [d/l] [select] |
Re: Help in read and write to file at a same time in same file.
by clueless newbie (Curate) on Apr 04, 2011 at 14:35 UTC
|
Just For Fun:
... to update a file "in place".
...
open(my $READER,'+<',$Filename_S)
or die "Can't open '$Filename_S'! $!";
open(my $WRITER,'+<',$Filename_S) # Don't use
+ '+>'
or die "Can't open '$Filename_S'! $!";
# The overflow buffer:
my @Buffer_a;
while (<$READER>) {
# Read (past tense) a line - buffer its replacement ...
# Modify the line here!
my $Update_s=...
push(@Buffer_a,$Update_s);
# Write from the overflow buffer if we can ...
while (@Buffer_a && length($Buffer_a[0]) < tell($READER)-tell(
+$WRITER)) {
# Enough room to write $Buffer_a[0] so write it ...
print $WRITER shift(@Buffer_a);
};
};
# Nothing more to read ...
close($READER)
or die "Can't close '$Filename_S'! $!";
# If there's anything in the buffer write it ...
while (@Buffer_a) {
print $WRITER shift(@Buffer_a);
};
# Truncate the file, in case, what we're writing is shorter than w
+hat we read
truncate($WRITER,tell($WRITER));
# ... and close
close($WRITER)
or die "Can't close '$Filename_S'! $!";
...
Be aware that if something should happen during the update one may be "up the creek without a paddle". | [reply] [d/l] |