2011-01-19 82 views
1

在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 ....... 
} 

回答

5

我不认为这是一个好主意,从文件中读取和像你一样在同一时间写入。您可以使用Tie::File。它将文件的行与数组绑定在一起。您可以根据需要修改阵列,然后在后台透明地修改文件。

+0

这正是我在找什么。谢谢! – 2011-01-19 15:42:14

6

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

这并没有帮助,除非你每次打算写行是相同的长度,您要更换线路(在这种情况下,你要寻找的工具seektell)。对于普通的编辑,标准的文件模型并没有削减它的位置。

幸运的是,Perl附带了一个功能,可以让您轻松进行所谓的“就地编辑模式”,其中源文件被重命名或取消链接,输出指向同名的新文件。通常通过启用-icommand-line switch以及-p-n开关进行行式编辑来使用它,但您也可以在使用$^Ispecial variable的程序中启用它。

示例代码:

{ # Create a scope to localize variables in. 
    # If you want to back up the originals, set $^I to ".bak" instead. 
    local $^I = ""; 
    # Set @ARGV to the file you want to process, or a list of files. 
    local @ARGV = ("file.txt"); 

    while (my $line = <>) { 
     # Process $line here. 
     print $line; 
    } 
} 
+0

只是给了这个尝试,它工作得很漂亮!谢谢! – 2011-01-19 15:55:26

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"; 

这样做的缺点是整个文件被重写,并且如果过早退出(例如,在调试期间),文件被搞乱了。

+1

无论如何,如果你所要做的就是关闭它,你不应该使用`flock $ fh,LOCK_UN`来解锁文件。 `close`会在文件关闭时解锁文件,但首先它会清除尚未写入的数据,防止竞争。 – hobbs 2011-01-19 23:16:42

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