Hi,

readline will be your friend.

Just have a look in the example mentioned this link:

https://www.tutorialspoint.com/perl/perl_readline.htm

Regards,
Ruprecht


Am 20.11.22 um 15:41 schrieb supp...@openmbox.net:
May i ask a question about reading file?

while(0){ print 'hi' }

Will never print hi.

cat 1.txt:
0

open FH, '1.txt' or die;
while(<FH>) { print 'hi' }

This will print hi.

Since $_ == 0 here, why while become true?

I am confused about this.

Regards

November 20, 2022, 8:57 PM, "Kang-min Liu" <gu...@gugod.org> wrote:


linux...@gmx.net writes:

I have a large file which has millions of lines.
  They are text only lines.
  If I have to change one line in the file, what's the efficient way?
  I don't want to slurp the whole file into memory, change that line and
  write the full content back to disk again.

It seems like the editing is line-based, I could recommend checking out
'perl -i' for doing in-place editing, if you are OK with regexp-based
search & replace -- it's basically the same as doing it in vim,

  perl -p -i.orig -e "s/hello/wow/" input.txt

This finds the first line that matces regexp ^foo$ , then replaces the
entire line with "foobar", shift the remainder of the file correctly and
wrote everything back to input.txt -- while keep an original copy of input.txt 
at
input.txt.orig

However that may match on multiple lines, if you know the line number in
advance, you could check the line number variable $.

  perl -p -i -e "s/^.+$/wow/ if $. == 2" input.txt

Note that doing this would still scan the entire input.txt line by
line. And adding `exit()` or `next` in the body of `-e` would make the
program finish early but would also truncate input.txt -- which is
probblay not what we want.

----

Alternatively, if you are looking for doing this with some code but not
with "perl" command, read on...

How efficient it could be depends a little bit on how the target line is
identified and the kind of editing that's required.

For sure you could avoid slupring by doing doing line-based changes
like:

  while (defined(my $line = <$fh>)) {
  ...
  }

If the editing is replacing $line with something that's equal in length,
then it can be pretty efficient -- just print the thing and the file is
modified in place.

If, say, we want to just just the 42nd line in the file, here's how I
would do:

  # Open as read-write mode.
  open my $fh, "+<", "input.txt";

  # Seek to the beginning of 42nd line
  my $lineno = 1;
  while (defined(my $line = <$fh>)) {
  $lineno += 1;
  last if $lineno == 42;
  }

  # Print the new content at the begging of 42nd line.
  print $fh $newcontent;

This is the most efficient scenario because the program can end here
without reading the remainder of input.txt.

However, if $newcontent is longer than the 42nd line, the program would
still finish and when we inspect the file, we'll see that the text in
$newcontext bleed over to the 43rd line and maybe further lines.

Similarly, if the $newcontent is shorter, the original conten in the
42nd line will only be partially replaced.

Most likely that's not the kind of editing we want to be doing.

Meaninng, if $newcontent is longer or shorter, the remainder of the file
should be shifted a few characters forward or backword and we want to
re-print those lines back to $fh -- which also requires a lot of bookkeeping
code just to get everything corner case right.

If the editing we want is rather generic I'd say we probably want to put
the output to a different file instead of doing in-place editing.

And we will still end up slurping the entire file, but only keeping one
line at a time in memory.

--
Cheers,
Kang-min Liu

--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


--
To unsubscribe, e-mail: beginners-unsubscr...@perl.org
For additional commands, e-mail: beginners-h...@perl.org
http://learn.perl.org/


Reply via email to