如何使用单个文件句柄修改文件的内容

How to modify content of a file using single file handle

我正在尝试使用 Perl 修改文件的内容。

以下脚本工作正常。

#!/usr/bin/perl

use strict;
use warnings;

open(FH,"test.txt") || die "not able to open test.txt $!";
open(FH2,">","test_new.txt")|| die "not able to opne test_new.txt $!";

while(my $line = <FH>)
{
        $line =~ s/perl/python/i;
        print FH2 $line;
}
close(FH);
close(FH2);

test.txt的内容:

im learning perl
im in File handlers chapter

test_new.txt中的输出:

im learning python
im in File handlers chapter

如果我尝试使用相同的文件句柄来修改文件的内容,那么我得不到预期的输出。以下是试图执行此操作的脚本:

#!/usr/bin/perl

use strict;
use warnings;

open(FH,"+<","test.txt") || die "not able to open test.txt $!";

while(my $line = <FH>)
{
        $line =~ s/perl/python/i;
        print FH $line;
}
close(FH);

test.txt 中的输出不正确:

im learning perl
im learning python
 chapter
 chapter

如何使用单个文件句柄修改文件内容?

@Сухой27 的回答

典型的perl在线者用的很开心的情况

perl -i -pe 's/perl/python/i'

perl 采用以下选项

  • -p : 逐行循环(每行分配到 $_ 并在评估 $_ 后打印)
  • -e :评估上面循环中的代码块(正则表达式将 $_ 作为默认操作数)
  • -i : 在 plcae 文件编辑中(如果你为 -i 传递参数,perl 会保留带有该扩展名的原始文件)

如果您运行低于脚本

perl -i.bak -pe 's/perl/python/i' test.txt

你会得到修改test.txt

im learning python
im in File handlers chapter

并获取以test.txt.bak

命名的原始文本文件
im learning perl
im in File handlers chapter

您不能从文件中删除(末尾除外)。
不能在文件中插入字符(末尾除外)。

您可以替换文件中的字符。
您可以附加到文件。
您可以缩短文件。
而已。

您假设您可以简单地将文件中的 "Perl" 替换为 "Python"。它们的长度不同,因此需要在文件中插入字符,而您不能这样做。

您可以有效地将字符插入文件,方法是将文件的其余部分加载到内存中,然后再将其写回两个字符。但是对于非常大的文件,这样做会很棘手。它也很慢,因为每次你想插入字符时你最终都会复制文件的一部分(可能非常大)。

就地修改的另一个问题是您无法从错误中恢复。如果出现问题,您将得到一个不完整或损坏的文件。

如果文件很小并且您可以接受在出现问题时丢失数据,最简单的方法是将整个文件加载到内存中。

 open(my $fh, '<+', $qfn)
    or die("Can't open \"$qfn\": $!\n");

 my $file = do { local $/; <$fh> };

 $file =~ s/Perl/Python/g;

 seek($fh, 0, SEEK_SET)
    or die $!;
 print($fh $file)
    or die $!;
 truncate($fh)
    or die $!;

一种更安全的方法是将数据写入一个新文件,然后在完成后重命名该文件。

 my $new_qfn = $qfn . ".tmp";
 open(my $fh_in, '<', $qfn)
    or die("Can't open  \"$qfn\": $!\n");
 open(my $fh_out, '<', $new_qfn)
    or die("Can't create \"$new_qfn\": $!\n");

 while (<$fh_in>) {
     s/Perl/Python/g;
     print($fh_out $_);
 }

 close($fh_in);
 close($fh_out);

 rename($qfn_new, $qfn)
    or die $!;

这种方法的缺点是它可能会更改文件的权限,并且硬链接将指向旧内容而不是新文件。您还需要创建文件的权限。