在Perl中,我试图逐行读取文件并处理每一行,并根据需要进行修改。 到目前为止,我正在阅读的唯一方法是将文件读入数组,根据需要修改数组的每个元素,然后在完成后将其输出回文件。
有没有更好的方法来做到这一点,也许某种方式我可以替换单行来进行?
现在,我的处理代码如下所示:
while (my $line = <FILE>)
{
# process line here
# ...........
print FILE $line;
}
我的代码似乎非常接近,除了它在我当前所在的行之后替换了一行,所以看起来如果我可以将文件指针向上移一行,它会写入正确的位置文件。
我是否在正确的轨道上?从这里我需要做什么来备份文件指针,以便它写入我正在阅读的同一行?
编辑:
在我收到的答案中,使用local $^I
和Tie::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 .......
}
答案 0 :(得分:7)
从这里我需要做什么来备份文件指针,以便写入我正在阅读的同一行?
这没有用,除非您打算写的每行与您要替换的行的长度相同(在这种情况下,您要查找的工具是seek和tell )。但是对于普通的编辑,标准文件模型不会因为原位替换而削减它。
幸运的是,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";
这样做的缺点是整个文件被重写,如果你太快退出(例如在调试期间),文件就会搞砸。