【问题标题】:How to modify content of a file using single file handle如何使用单个文件句柄修改文件的内容
【发布时间】:2017-09-18 12:46:14
【问题描述】:

我正在尝试使用 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

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

【问题讨论】:

  • 实际上,您总是希望写入另一个文件,即使perl -i -pe 's/perl/python/i' test.txt 以这种方式工作。或者,您可以一次读取整个文件,进行更改并将整个文件写回同一个句柄。
  • @Сухой27 你能解释一下命令中选项的作用,即 -i -pe
  • 这是文件句柄,不是处理程序。
  • 你有完整的answer by ikegami,这是另一个post,也展示了如何保持相同的inode。

标签: perl filehandle


【解决方案1】:

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

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

您想象您可以简单地将文件中的“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 $!;

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

【讨论】:

    【解决方案2】:

    正如@Сухой27 回答的那样

    perl onliner 用起来很舒服的典型情况。

    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
    

    【讨论】:

    • 注意这里使用了两个句柄。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-09
    • 2012-11-24
    • 1970-01-01
    相关资源
    最近更新 更多