【问题标题】:Perl script works if I open and close the file and start again but not if I try to run it without closing the file and use seek如果我打开和关闭文件并重新开始,Perl 脚本可以工作,但如果我尝试在不关闭文件的情况下运行它并使用 seek
【发布时间】:2014-12-15 01:39:34
【问题描述】:

我有一个脚本可以打开 .txt 文件、创建一个数组并进行一些替换。然后我关闭并打开文件句柄并根据四列删除重复行并保留最新行。这一切都是我想要的。但是当我尝试在脚本中间没有打开和关闭的情况下运行它时,我得到一个空白文件。

#!/usr/bin/perl
use strict;
use warnings;
#use diagnostics;

my $file = "c:\\tmp.txt";
open( my $fh, "<", $file ) or die $!;

my $OUTNET = "c:\\NETtmp.txt";
open( OUTPUT, ">", "$OUTNET" ) or die $!;
my @array;

foreach (<$fh>) {
    chomp;
    if ($_ =~ m/^\s+\d/) {

        $_ =~ s/^\s+//g;
        $_ =~ s/\s+$//g;
        $_ =~ s/\s+/,/g;
        print  " $_  \n";
        printf OUTPUT "$_  \n";
    }
}
close OUTPUT; # Do I need to save and then reopen the file here?

my $file2 = "c:\\NETtmp.txt";
my $OUTNET2 = "c:\\final.txt";

open my $in,  '<', $file2 or die $!;
open my $out, '>', $OUTNET2 or die $!;
seek $in, 0, 0;
my %hash;

while (<$in>) {
    my $key = join ',', ( split /,/ )[ 1, 2, 3, 4 ];
    printf $out $_ unless $hash{$key}++;
}
close $out;
close $in;

【问题讨论】:

  • 你认为( split /,/ )[ 1, 2, 3, 4 ]创建了一个由4个不同元素组成的字符串吗?因为它没有。
  • 您没有运行此代码,因为它不严格兼容。发布有关您实际上并未运行的代码的问题是毫无用处的。您应该始终剪切和粘贴所有相关代码,最好创建一个sscce
  • 这对我的 $file = "c:\\tmp.txt" 有效; open(my $fh, ") { chomp; if ( $_ =~ m/^\s+\d/ ) { $_ =~ s/^\s+//g; $_ =~ s/\s+$//g; $_ =~ s/\s+/,/g;推@array, "$_ \n"; }} 我的 $OUTNET2 = "c:\\final.txt";打开我的 $out, '>', $OUTNET2 或者死 $!;我的 %hash; for (@array) { my $key = join ',', ( split /,/ )[ 1, 2, 3, 4 ];打印 $out $_ 除非 $hash{$key}++; }

标签: perl


【解决方案1】:

这段代码很糟糕,所以我将把它通读一遍并在我进行的时候发表评论。

#!/usr/bin/perl
use strict;
use warnings;
#use diagnostics;

使用strictwarnings 是个好主意。

my $file = "c:\\tmp.txt";
open( my $fh, "+>", $file ) or die $!;

open 使用+ 模式几乎总是错误的做法。如果您想要替换内容,那么写入新文件并将其复制到旧文件上会容易得多。

my $OUTtmp = "c:\\OUTtmp.txt";
open( OUTPUT, ">", "$OUTtmp" ) or die;

您永远不必像这样引用变量。我假设您正在尝试强制字符串化,但 Perl 在需要时会自动执行此操作。在这种情况下,"$OUTtmp"$OUTtmp 完全相同。

my @array;

请注意,@array 现在为空。

foreach (<$fh>) {
    chomp;
    if ( $_ =~ m/^\s+\d/ ) {
        $_ =~ s/^\s+//g;
        $_ =~ s/\s+$//g;
        $_ =~ s/\s+/,/g;
        # print  " $_  \n";
        # printf OUTPUT "$_  \n";
    }
}

这个循环只是遍历文件并更改行,但不会将它们存储在任何地方。所以任何更改都会丢失。

#close $fh;
#close OUTPUT;
seek $fh, 0, 0;
my %hash = @array;

记住@array 是空的,所以现在%hash 也是空的。

while (<$fh>) {
    my $key = ( split /,/ )[ 1, 2, 3, 4 ];

这不太可能达到您的预期。您试图将 4 个标量值分配给一个标量值,而这永远不会发生。标量上下文中的列表切片返回它将在列表上下文中返回的最后一个值。例如:

>perl -E"my $key = ( split /,/, 'a,b,c,d,e,f' )[ 1, 2, 3, 4 ]; say $key"
e

    printf OUTPUT $_ unless $hash{$key}++;
}

我认为这是您尝试读取文件并对其进行重复数据删除。这只会重用原始文件而不做任何更改,因为在前一个循环中执行的更改会丢失。

close $fh;
close OUTPUT;

程序结束时文件会自动关闭,因此您无需执行此操作。除非您正在处理光盘写入错误。

【讨论】:

  • Re ""$OUTtmp"$OUTtmp 完全一样",不是这样。但是,除非您知道您有需要强制字符串化的罕见情况之一,否则您应该使用$OUTtmp
【解决方案2】:

文件模式“+>”破坏文件。将文件模式更改为 +

open( my $fh, "+<", $file ) or die $!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 2013-03-13
    • 2016-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多