Perl读取搜索告诉和文本文件。读取的字节太多。图层和换行处理

时间:2013-05-29 11:56:40

标签: perl seek tell binmode

我有一个Perl脚本,可以在发现感兴趣的内容时分析存储文件偏移的文本文件(可以是UNIX或Windows行结尾)。

open(my $fh, $filename);
my $groups;
my %hash;
while(<$fh>) {
   if($_ =~ /interesting/ ) {
      $hash{$groups++}{offset} = tell($fh);
   }
}
close $fh;

然后在脚本中我想生成文本文件的'n'个副本,但每个'有趣'区域都有其他内容。为了达到这个目的,我遍历了偏移的散列:

foreach my $group (keys %hash) {
   my $href = $hash{$group};
   my $offset = $href->{offset};

   my $top;
   open( $fh, $file);
   read( $fh, $top, $offset);
   my $bottom = do{local $/; <$fh>};
   close $fh;

   $href->{modified} = $top . "Hello World\n" . $bottom;
}

问题是read命令读取的字节太多。我怀疑这是一个行结束问题,因为字节数(字符?)输出与行号相同。使用Notepad ++,tell()命令将实际偏移返回到兴趣点,但在read()中使用该偏移值会返回超出目标点的字符。

我尝试在binmode($fh)之前的open()命令之后直接添加read()。这确实在文本文件中找到了正确的位置,但随后我得到(CR + CRLF)输出并且文本文件充满了双回车。

我玩过图层:crlf,:bytes,但没有改进。

有点卡住了!

3 个答案:

答案 0 :(得分:0)

  • 具有连续整数范围的哈希作为键应该是一个数组。

  • 您每次出现/interesting/时都会存储整个文件的副本

  • 听起来你需要做的就是这个

    open(my $fh, $filename);
    while (<$fh>) {
      print;
      print "Hello World\n" if /interesting/;
    }
    

答案 1 :(得分:0)

来自perldoc -f read

read FILEHANDLE,SCALAR,LENGTH,OFFSET
read FILEHANDLE,SCALAR,LENGTH

所以,当你这样做时:

read( $fh, $top, $offset);

你的$offset实际上是一个长度。确定需要阅读的字符数。 read不遵循行结尾,它读取指定的字节数。

如果您想阅读一行,请不要使用read,请使用:

seek($fh, $offset, 0);
$top = <$fh>;

您的文件是否包含两个新行,或者您是否添加了一个print语句?

答案 2 :(得分:0)

当输入文件不是巨大的时候,我处理这个问题的标准方法是将文件插入并标准化行结尾,将每一行存储为数组元素。我有时不得不在同一批文件中处理Windows(CR + LF)和UNIX(仅LF)和Mac(仅CR)行结尾。同样的脚本也需要在所有三个平台上正确运行。

当我不得不处理这些事情时,我通常采取腰带和括号的方法。一种应该工作的方式:

sub read_file_into_array
{
    my $file = shift;
    my ($len, $cnt, $data, @file);

    open my $fh, "<", $file         or die "Can't read $file: $!";
    seek $fh, 0, 2                  or die "Can't seek $file: $!";
    $len = tell $fh;
    seek $fh, 0, 0                  or die "Can't seek $file: $!";

    $cnt = read $fh, $data, $len;
    close $fh;

    $cnt == $len or die "Attempted to read $len bytes; got $cnt";

    $data =~ s/\r\n/\n/g;       # Convert DOS line endings to UNIX
    $data =~ s/\r/\n/g;         # Convert Mac line endings to UNIX

    @file = split /\n/, $data;  # Split on UNIX line endings

    return \@file;
}

然后对@file中的行进行所有处理。对于“有趣”标记,您将存储数组索引而不是文件偏移量。数组索引本质上是原始文件中的行号,从0开始计数而不是1。

要实际扩充文件,而不是循环遍历散列键,为什么不构造一个由line-number =&gt;组成的散列。 thing-to-append对,生成如下的增强文件:

sub generate_augmented_file
{
    my $file   = shift @_;   # array ref
    my $extras = shift @_;   # hash ref of line => extra pairs
    my $text;        

    foreach my $line ( 0 .. scalar( $file ) - 1 )
    {
        $text .= $file->[$line];
        $text .= $extras->{$line} if defined $extras->{$line};
        $text .= "\n";
    }

    return $text;
}