在这个例子中,我想原地修改文件(没有饼图):
# Initialise file
open my $fh, '>', 'test';
print $fh 'I love apples';
close $fh;
# Do the replacement
open $fh, '+<', 'test';
s/love/hate/ while(<$fh>);
close $fh;
# Test content (should be 'I hate apples')
open $fh, '<', 'test';
print while(<$fh>);
close $fh;
不幸的是这个例子不起作用。我只找到了这个丑陋的解决方案:
# Do the replacement
open $fh, '<', 'test';
my $out;
my $changes;
while(<$fh>) {
$changes += $_ =~ s/love/hate/;
$out.=$_;
}
if($changes) {
open $fh, '>', 'test';
print $fh $out;
}
close $fh;
有更好的解决方案吗?
要求:如果有什么要改变,我只想触摸我的文件。 提示:我在Windows / Cygwin上:(
答案 0 :(得分:2)
除非替换长度相同;你必须从替换点向前重写文件,以插入/删除其中的一个字母。
-i
选项通常使用临时文件实现。所有更改都将写入临时文件,该文件最后重命名为原始文件名:
$ perl -i -pe's/a/bc/g' input1
$ <input2 perl -pe's/a/bc/g' >output && replace output input2
$ <input3 perl -pe's/a/bc/g' | sponge input3
即,
while(<$fhorig>) {
$changed += $_ =~ s/love/haaate/;
print $fhtmp $_;
}
# close, fsync files..
rename $tmp, $orig if $changed;
如果输入文件很小;你可以在没有临时文件的情况下在内存中进行更改。你在问题中的代码就是这样做的。
如果替换长度相同,那么您可以mmap该文件并在其中进行更改。 Windows和Unix都支持mmap。它允许使用大文件,就好像它是一个字符串,或者你可以使用read / seek / write来模拟它。
答案 1 :(得分:2)
相关文件:
在您的情况下,我建议使用$INPLACE_EDIT
作为上述两个常见问题条目之一的模型。
use strict;
use warnings;
use autodie;
my $file = 'test';
# Initialise file
open my $fh, '>', $file;
print $fh <DATA>;
close $fh;
# Do the replacement
local @ARGV = $file;
local $^I = '.bak';
while (<>) {
s/love/hate/;
print;
}
unlink "$file$^I"; # Optionally delete backup
# Test content (should be 'I hate apples')
open $fh, '<', 'test';
print <$fh>;
close $fh;
__DATA__
I love apples
I love oranges
I love bananas
输出:
I hate apples
I hate oranges
I hate bananas
注意:如果您使用的是Windows,那么您需要为-i
指定备用扩展程序。因此,我总是这样做是跨平台兼容的。