1
    this
    is just
    an example.

让我们假设上面是out.txt。我想读取out.txt并写入同一个文件。

    <Hi >
    <this>
    <is just>
    <an example.>

修改out.txt。我想在某些行的开头和结尾添加标签。由于我将多次读取该文件,因此我无法每次都将其写入不同的文件。

编辑 1 我尝试使用"+<",但它给出的输出如下:

Hi
this
is just
an example.
<Hi >
<this>
<is just>
<an example.>
 **out.txt**

编辑 2 代码供参考:

open(my $fh, "+<", "out.txt");# or die "cannot open < C:\Users\daanishs\workspace\CCoverage\out.txt: $!";
     while(<$fh>)
     {
        $s1 = "<";
        $s2 = $_;
        $s3 = ">";
        $str = $s1 . $s2 . $s3;
        print $fh "$str";
     }
4

5 回答 5

8

你正在尝试做的事情的想法是有缺陷的。文件开头为

H  i  /  t  h  i  s  /  ...

如果您要对其进行更改,则在处理第一行后它将如下所示:

<  H  i  >  /  i  s  /  ...

注意你是如何破坏“th”的?您需要制作文件的副本,修改副本,用副本替换原始文件。

最简单的方法是在内存中制作这个副本。

my $file;
{ # Read the file
   open(my $fh, '<', $qfn)
      or die "Can't open \"$qfn\": $!\n";
   local $/;
   $file = <$fh>;
}

# Change the file
$file =~ s/^(.*)\n/<$1>\n/mg;

{ # Save the changes
   open(my $fh, '>', $qfn)
      or die "Can't create \"$qfn\": $!\n";
   print($fh $file);
}

如果您想改用磁盘:

rename($qfn, "$qfn.old")
   or die "Can't rename \"$qfn\": $!\n";

open(my $fh_in, '<', "$qfn.old")
      or die "Can't open \"$qfn\": $!\n";
open(my $fh_out, '>', $qfn)
      or die "Can't create \"$qfn\": $!\n";

while (<$fh_in>) {
   chomp;
   $_ = "<$_>";
   print($fh_out "$_\n");
}

unlink("$qfn.old");

使用技巧,上面可以简化为

local @ARGV = $qfn;
local $^I = '';
while (<>) {
   chomp;
   $_ = "<$_>";
   print(ARGV "$_\n");
}

或作为单行:

perl -i -pe'$_ = "<$_>"' file
于 2012-09-28T05:10:57.347 回答
5

读取内存中的内容,然后在写入文件时准备所需的字符串。(需要将 SEEK_SET 设置为零字节。

#!/usr/bin/perl

open(INFILE, "+<in.txt");
@a=<INFILE>;
seek INFILE, 0, SEEK_SET ;
foreach $i(@a)
{ 
    chomp $i;
    print INFILE "<".$i.">"."\n";
}

如果您担心在内存中读取的数据量,您将不得不创建一个临时结果文件,最后将结果文件复制到原始文件。

于 2012-09-28T10:43:56.557 回答
2

您可以使用Tie::File轻松随机访问文件中的行:

use Tie::File;
use strict;
use warnings;

my $filename = "out.txt";
my @array;
tie @array, 'Tie::File', $filename or die "can't tie file \"$filename\": $!";

for my $line (@array) {
  $line = "<$line>";
  # or $line =~ s/^(.*)$/<$1>/g; # -- whatever modifications you need to do
}

untie @array;

免责声明:当然,此选项仅在文件未与其他进程共享时才可行。否则,您可以flock在修改文件时使用它来阻止共享访问。

Disclaimer-2(感谢 ikegami):如果您必须编辑大文件并且担心性能,请不要使用此解决方案。对于小文件(小于 2MB,尽管可以使用memoryarg 进行配置),大部分性能损失都会得到缓解。

于 2012-09-28T05:12:30.113 回答
1

一种选择是打开文件两次:以只读方式打开一次,读取数据,关闭它,处理它,再次以读写方式打开它(不附加),写入数据,然后关闭它。这是一个很好的做法,因为它可以最大限度地减少打开文件的时间,以防其他人需要它。

如果您只想打开一次,那么您可以使用+<文件类型 - 只需使用seek读取和写入之间的调用返回文件开头即可。否则,您完成阅读,位于文件末尾,然后开始在那里写入,这就是您得到所看到行为的原因。

于 2012-09-28T05:02:31.347 回答
0

需要指定

use Fcntl qw(SEEK_SET);

为了使用

seek INFILE, 0, SEEK_SET;

感谢 user1703205 的示例。

于 2014-04-24T13:25:01.773 回答