比较两个文件名数组的差异

时间:2016-04-19 12:24:12

标签: arrays perl

下面是我的尝试,并将文本文件中的所有文件名加载到一个数组中,并将该数组与位于单独目录中的文件名进行比较。我想确定目录中的文件名而不是文件中的文件名,以便我可以处理这些文件。我能够成功加载两个目录的内容,但比较操作输出的所有文件不仅仅是差异。

提前感谢您的帮助。

use File::Copy;
use Net::SMTP;
use POSIX;
use constant DATETIME => strftime("%Y%m%d", localtime);
use Array::Utils qw(:all);
use strict;
use warnings;


my $currentdate = DATETIME;
my $count;
my $ErrorMsg = "";
my $MailMsg = "";
my $MstrTransferLogFile = ">>//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt";
my $DailyLogFile = ">//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Daily_Transfer_Log_" . DATETIME . ".txt";
my $InputDir = "//CFVFTP/Users/ssi/Transfer_Logs/folder1/";
my $MoveDir = "//CFVFTP/Users/ssi/Transfer_Logs/folder2/";
my $filetouse;
my @filetouse;
my $diff;
my $file1;
my $file2;
my %diff;

open (MSTRTRANSFERLOGFILE, $MstrTransferLogFile) or $ErrorMsg = $ErrorMsg . "ERROR: Could not open master transfer log file!\n";
open (DAILYLOGFILE, $DailyLogFile) or $ErrorMsg = $ErrorMsg . "ERROR: Could not open daily log file!\n";


#insert all files in master transfer log into array for cross reference
open (FH, "<//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt") or $ErrorMsg = $ErrorMsg . "ERROR: Could not open master log file!\n";
my @master = <FH>;
close FH;
print "filenames in text file:\n";
foreach $file1 (@master) { print "$file1\n"; }
print "\n";

#insert all 835 files in Input directory into array for cross reference
opendir (DIR, $InputDir) or $ErrorMsg = $ErrorMsg . "ERROR: Could not open input directory $InputDir!\n";
my @list = grep { $_ ne '.' && $_ ne '..' && /\.835$/  } readdir DIR;
close(DIR);
print "filenames in folder\n";
foreach $file2 (@list) { print "$file2\n"; }
print "\n";

#get the all files in the Input directory that are NOT in the master transfer log and place into @filetouse array
@diff{ @master }= ();;
@filetouse = grep !exists($diff{$_}), @list;;

print "difference:\n";
foreach my $file3 (@filetouse) { print "$file3\n"; }

print DAILYLOGFILE "$ErrorMsg\n";
print DAILYLOGFILE "$MailMsg\n";

close(MSTRTRANSFERLOGFILE);
close(DAILYLOGFILE); 

这是输出的样子:

    filenames in text file:
    160411h00448car0007.835


    filenames in folder
    160411h00448car0007.835
    160411h00448car0008.835
    160418h00001com0001.835

    difference:
    160411h00448car0007.835
    160411h00448car0008.835
    160418h00001com0001.835

2 个答案:

答案 0 :(得分:1)

这可以帮助您做您需要的事情。它将INPUT_DIR中所有文件的名称存储为散列%files中的键,然后删除LOG_FILE中找到的所有名称。其余部分打印

此程序使用autodie,因此无需显式检查IO操作是否成功。它首次在v5.10.1中的Perl 5核心中提供

use strict;
use warnings 'all';
use v5.10.1;
use autodie;
use feature 'say';

use constant LOG_FILE  => '//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt';
use constant INPUT_DIR => undef;

chdir INPUT_DIR;

my %files = do {
    opendir my $dh, '.';
    my @files = grep -f, readdir $dh;
    map { $_ => 1 } @files;
};

my @logged_files = do {
    open my $fh, '<', LOG_FILE;
    <$fh>;
};
chomp @logged_files;

delete @files{@logged_files};

say for sort keys %files;


更新

经过大量磨损后,我发现原始代码

use strict;
use warnings 'all';
use v5.10.1;
use autodie;
use feature 'say';

use Time::Piece 'localtime';

use constant DATETIME  => localtime()->ymd('');
use constant XFR_LOG   => '//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Mstr_Transfer_Log.txt';
use constant DAILY_LOG => '//CFVFTP/Users/ssi/Transfer_Logs/Artiva/ARTIVA_Daily_Transfer_Log_' . DATETIME . '.txt';
use constant INPUT_DIR => '//CFVFTP/Users/ssi/Transfer_Logs/folder1/';
use constant MOVE_DIR  => '//CFVFTP/Users/ssi/Transfer_Logs/folder2/';

chdir INPUT_DIR;

my @master = do {
    open my $fh, '<', XFR_LOG;
    <$fh>;
};
chomp @master;

my @list = do {
    opendir my $dh, '.';
    grep -f, readdir $dh;
};

my %diff;
@diff{ @master } = ();

my @filetouse = grep { not exists $diff{$_} } @list;

如您所见,它与我的解决方案非常相似。以下是关于原始

的一些注意事项
  • 始终使用词法文件句柄。对于open FH, ...,文件句柄是全局,除非您明确地或直到程序终止,否则永远不会关闭。相反,open my $fh, ...离开perl以关闭当前块末尾的文件句柄

  • 始终使用open的三参数形式,以便打开模式与文件名分开,并且永远不要将打开模式作为文件名的一部分。您打开了两次相同的文件:一次为$MstrTransferLogFile,以>>开头,一次明确,因为您需要读取权限

  • 程序很少能够从IO操作错误中恢复。除非您正在编写故障安全软件,否则无法打开或读取文件或目录意味着该程序将无法实现其目的。这意味着没有理由积累错误消息列表 - 代码只有die才能成功

  • 如果您需要处理目录,readdir的输出非常混乱,因为它包含伪目录...。但是如果你只想要文件,那么一个简单的grep -f, readdir $dh将为你抛出这些文件

  • grep的形式通常更具可读性,not!更明显。因此grep !exists($diff{$_}), @list更加清晰,因为grep { not exists $diff{$_} } @list

  • 除非您的代码真的奇怪,否则评论通常会增加更多的噪音和混乱,并使结构模糊不清。让你的代码看起来像它的代码,所以你不必解释它

哦,不要在开始时把你可能需要的所有东西扔进去“以防万一”。编写代码,好像它就在那里,编译器会告诉你缺少什么

我希望有帮助

答案 1 :(得分:0)

首先,使用哈希来存储已处理的文件。然后,只需检查散列中是否存在文件。

(我已经更改了一些变量名称以使答案更清晰。)

foreach my $file (@dir_list) {
   push @to_process, $file unless ($already_processed{$file});
}

(这可能是一个单行,但首先要以最扩展的形式工作。)

如果你坚持你的阵列,这看起来效率低得多

foreach my $file (@dir_list) {
   push @to_process, $file unless (grep (/^$file$/, @already_processed));
}

(再次可能是一个单行,但......)

相关问题