如何根据需要修改行时逐行读取文件?

时间:2011-01-19 07:53:32

标签: perl

在Perl中,我试图逐行读取文件并处理每一行,并根据需要进行修改。 到目前为止,我正在阅读的唯一方法是将文件读入数组,根据需要修改数组的每个元素,然后在完成后将其输出回文件。

有没有更好的方法来做到这一点,也许某种方式我可以替换单行来进行?

现在,我的处理代码如下所示:

while (my $line = <FILE>)
{
    # process line here
    # ...........

    print FILE $line;
}

我的代码似乎非常接近,除了它在我当前所在的行之后替换了一行,所以看起来如果我可以将文件指针向上移一行,它会写入正确的位置文件。

我是否在正确的轨道上?从这里我需要做什么来备份文件指针,以便它写入我正在阅读的同一行?


编辑:

在我收到的答案中,使用local $^ITie::File都很顺利。 我最终选择Tie::File,所以我不必打印出文件的每一行。这样,如果在脚本中途发生了某些事情,我的文件就不会搞砸了。

我的新代码如下:

use Tie::File;

chomp(my $filename = $ARGV[0]);
tie my @array, 'Tie::File', $filename or die $!;

foreach my $line(@array)
{
    # ...... line processing happens here .......
    # ...... $line is automatically written to file if $line is changed .......
}

4 个答案:

答案 0 :(得分:7)

  

从这里我需要做什么来备份文件指针,以便写入我正在阅读的同一行?

这没有用,除非您打算写的每行与您要替换的行的长度相同(在这种情况下,您要查找的工具是seektell )。但是对于普通的编辑,标准文件模型不会因为原位替换而削减它。

幸运的是,Perl附带了一个功能,可以轻松实现您所需的功能,称为“就地编辑模式”,其中源文件可以重命名或取消链接,输出定向到具有相同名称的新文件。通常情况下,-i command-line switch-p-n开关一起启用以进行逐行编辑,但您也可以使用{在程序中启用它{1}} special variable

示例代码:

$^I

答案 1 :(得分:5)

我认为从文件中读取并同时写入文件并不是一个好主意。

您可以使用Tie::File。它将文件的行绑定到数组。您可以根据需要修改数组,然后在后台透明地修改文件。

答案 2 :(得分:1)

可能与问题无关,但可以在命令行上对就地文件进行快速更改,例如

# convert MS line endings to UNIX:
perl -p -i -e 's{\r\n}{\n}' my_file.txt

代码中的行是$ _(-e的参数)并打印出行,因此它就是这样的就地版本:

perl -e '$line = $_; $line =~ s{\r\n}{\n}; print $line' < windows.txt > unix.txt  

答案 3 :(得分:0)

我倾向于按照this answer中的假设(参见sub precommit_hook):

首先,将整个文件读入一个数组:

open my $handle,'<:utf8',$name 
    or croak "Error reading file contents of $name\n";
my @content = <$handle>;
close $handle or croak "unable to close";

然后,处理数组的每一行并将其写入文件:

# now, write it, ignoring the comment lines
open my $handle, '>:utf8', $name
or croak "Opening $name for writing failed\n";
flock $handle, LOCK_EX;

foreach my $line(@content){
  # TODO: modify the line here
  print {$handle} $line . "\n";
}

close $handle or croak "unable to close";

这样做的缺点是整个文件被重写,如果你太快退出(例如在调试期间),文件就会搞砸。