【问题标题】:Open two text files, process them and write to separate files打开两个文本文件,处理它们并写入单独的文件
【发布时间】:2017-10-13 17:32:45
【问题描述】:

我正在使用 Perl 打开两个文本文件,处理它们,然后将输出写入另一个文件。

我有一个文件INPUT,每一行都是客户。我会将每一行处理成变量,这些变量将用于替换另一个文件TEMP 中的文本。应将结果写入每个客户的单独文件中,OUTPUT

我的程序似乎只处理第一个文件。其余文件保持为空,没有输出。

#!/usr/bin/perl -w

if ( $#ARGV < 0) {
    print "Usage: proj5.pl <mm/dd/yyyy>\n";
    exit;
}

my $date = $ARGV[0];

open(INFO, "p5Customer.txt") or die("Could not open p5Customer.txt file\n");
open(TEMP, "template.txt")   or die("Could not open template.txt file\n");

my $directory = "Emails";
mkdir $directory unless(-e $directory);

foreach $info (<INFO>){

    ($email, $fullname, $title, $payed, $owed) = split /,/, $info;
    next if($owed < $payed);
    chomp($owed);

    $filepath = "$directory/$email";
    unless(open OUTPUT, '>>'.$filepath){
        die "Unable to create '$filepath'\n";
    }

    foreach $detail (<TEMP>){
        $detail =~ s/EMAIL/$email/g;
        $detail =~ s/(NAME|FULLNAME)/$fullname/g;
        $detail =~ s/TITLE/$title/g;
        $detail =~ s/AMOUNT/$owed/g;
        $detail =~ s{DATE}{$date}g;
        print OUTPUT $detail;
    }

    close(OUTPUT);
}

close(INFO);
close(TEMP);

【问题讨论】:

  • 总是use strict,除非你有一个非常充分的理由。

标签: perl file output


【解决方案1】:

如前所述,每次读取模板文件时都需要再次打开它。你的代码还有很多其他问题

  • 总是use strictuse warnings 'all' 并用my 声明每个变量,使其尽可能接近首次使用的位置

  • $#ARGV@ARGV的最后一个元素的索引,所以$#ARGV &lt; 0写成@ARGV &lt; 1会好很多

  • 你应该使用词法文件句柄,并且open的三参数形式,所以open(INFO, "p5Customer.txt")应该是open my $info_fh, '&lt;', "p5Customer.txt"

  • 你应该使用while而不是for来读取文件

  • 使用默认变量$_进行短循环更容易

  • 如果你不打算使用正则表达式中的子字符串是没有意义的,所以(NAME|FULLNAME)应该是NAME|FULLNAME

  • 在程序结束之前关闭输入文件是没有意义的

使用现有的模板系统也更好,例如 Template::Toolkit

这应该适合你

#!/usr/bin/perl

use strict;
use warnings 'all';

if ( @ARGV < 1 ) {
    print "Usage: proj5.pl <mm/dd/yyyy>\n";
    exit;
}

my $date = $ARGV[0];

open my $info_fh, '<', 'p5Customer.txt' or die qq{Could not open "p5Customer.txt" file: $!};

my $directory = "Emails";
mkdir $directory unless -e $directory;

while ( <$info_fh> ) {

    chomp;
    my ($email, $fullname, $title, $payed, $owed) = split /,/;
    next if $owed < $payed;

    open my $template_fh, '<', 'template.txt' or die qq{Could not open "template.txt" file: $!};

    my $filepath = "$directory/$email";
    open my $out_fh, '>', $filepath or die qq{Unable to create "$filepath": $!};

    while ( <$template_fh> ) {

        s/EMAIL/$email/g;
        s/FULLNAME|NAME/$fullname/g;
        s/TITLE/$title/g;
        s/AMOUNT/$owed/g;
        s/DATE/$date/g;

        print $out_fh $_;
    }

    close($out_fh);
}

【讨论】:

  • 哇这解决了它。这是我的第一个 Perl 程序,我知道我的代码可能有一些问题,感谢您指出它们并提供提示。
【解决方案2】:

您的问题是 TEMP 循环在 inside INPUT 循环中,因此当 INPUT 循环仍在 INPUT 文件的第一行时,TEMP 循环将结束。

最好将 TEMP 文件数据存储到哈希表中,并在 INPUT 循环内处理 TEMP 哈希表。

祝你好运。

【讨论】:

  • 或者,在INFO 循环内打开和关闭TEMP
  • 或者,seek TEMP, 0, 0 在每次读取它之前
  • 老实说,我不喜欢 INFO 循环中的打开/关闭 TEMP,因为这会产生很多不必要的处理(文件访问与哈希表)。如果 INFO 文件包含数千行,则代码将打开/关闭 TEMP 数千次。
  • Borodin,您的方法可以解决 OP 的问题,但它仍然是从 TEMP 文件中读取(文件 I/O 确实不如内存中的哈希表最佳) .无论如何,JMHO。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-08-16
  • 1970-01-01
  • 2012-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-18
相关资源
最近更新 更多