打开文件并进行调整并覆盖该文件,不进行备份

时间:2018-08-02 18:22:17

标签: perl file-io

我有以下三行内容:

rename($file_path, $file_fh.'.bak');
open( my $file_IN_fh, '<' , $file_path.'.bak') || die "die message";
open( my $file_OUT_fh, '>' , $file_path) || die "die message";

效果很好。它使我可以浏览文件while(<$file_IN_fh>),使用脚本(s///gif()进行一堆更改,以确定行是否停留,等等),然后写入输出文件。最后,我得到了编辑的文件,并且文件名未更改

我的问题是我现在不再需要备份文件,因此我想用类似的代码替换不会创建备份文件的代码,并来回评论这三个文件如果我的需求发生变化,这些年来可以排成一行。

我如何不在命令行中进行这种编辑?

3 个答案:

答案 0 :(得分:4)

一种基本方法是逐行读取文件并将所需的输出行写入临时文件,然后将其重命名以覆盖原始文件。

use File::Copy qw(move);

open my $fh, '<', $file or die "Can't open $file: $!";
open my $fh_out, '>', $outfile or die "Can't open $outfile: $!";

while (<$fh>) {
    next if /line_to_skip/;
    s/patt/repl/g;
    print $fh_out $_;
}
close $_ for ($fh, $fh_out);

move ($outfile, $file) or die "Can't move $outfile to $file: $!";

这通常由“就地”编辑文件的工具完成(具有额外的安全性,检查和灵活性)。由于$outfile是临时使用File::Tempclose-ing文件时添加检查。 请注意,这会更改文件的索引节点号,这对于某些应用程序可能很重要。

如果文件不大,您可以简化并先阅读

open my $fh, '<', $file or die "Can't open $file: $!";

my @lines = <$fh>;

open    $fh, '>', $file or die "Can't open $file for writing: $!";

for (@lines) {
    next if /line_to_skip/;
    s/patt/repl/g;
    print $fh_out $_;
}

close $fh;

由于>模式会截断现有的inode数据,因此保留了inode编号。


如果确实存在问题,您仍然可以保留相同的inode。写入临时文件后,将其打开以进行读取,然后打开原始文件以进行写入;截断该索引节点的内容。然后将临时文件复制到原始文件。关闭句柄并删除临时文件。

答案 1 :(得分:2)

如果文件很大,那么我会问为什么您要避免使用临时文件。否则,建议将文件加载到内存中,进行修改,然后再写回。

use File::Slurp qw( read_file write_file );

my $in = read_file($qfn, array_ref => 1);

my @out;
while (defined( $_ = shift(@$in) )) {
   s/a/b/g;               # For example.
   push @out, $_ if /c/;  # For example.
}    

write_file($qfn, \@out);

我避免通过使用两个数组来使用昂贵的splice

请注意,使用Tie :: File可能会节省一行代码,但这会快30倍 [1] ,并且可能使用更少的内存(尽管节省内存是Tie :: File的目标)。 Tie ::文件永远无法解决!


  1. 这不一定代表所有Tie :: File的使用,但是我确实为Tie :: File设置了比某些基本任务花费30倍长的时间。这意味着使用Tie :: File只需1分钟即可花费2秒的工作时间!

答案 2 :(得分:1)

看看Tie::File模块。它是一个核心模块,因此不需要安装,其代码非常简单

use Tie::File;

tie my @file, 'Tie::File', $filepath or die $!;

此后,数组@file将保存文件的内容,每个元素占一行,并且对该数组的任何更改都将反映在文件中。所有数组操作(例如pushsplice等)都可以正常运行

请注意,文件的第一行位于数组的元素零等中。