如何使用Perl判断两个文件的内容是否相同?

问题描述 投票:0回答:3

这个问题来自于需要确保我对代码所做的更改不会影响它输出到文本文件的值。理想情况下,我会滚动一个 sub 来接受两个文件名和

return 1
return 0
,具体取决于内容是否相同、空格等。

鉴于文本处理是 Perl 的强项,比较两个文件并确定它们是否相同应该很容易(下面的代码未经测试)。

use strict;
use warnings;

sub files_match {

    my ( $fileA, $fileB ) = @_;
    open my $file1, '<', $fileA;
    open my $file2, '<', $fileB;

    while (my $lineA = <$file1>) {

        next if $lineA eq <$file2>;
        return 0 and last;
    }

    return 1;
}

我能想到的唯一方法(无 CPAN 模块)是打开有问题的两个文件,并逐行读取它们,直到发现差异。如果没有发现差异,则文件必须相同。

但这种方法是有限且笨拙的。如果两个文件中的总行数不同怎么办?我应该打开并关闭以确定行数,然后重新打开以扫描文本吗?恶心。

我在 perlfaq5 中没有看到任何与此相关的内容。我想远离模块,除非它们带有核心 Perl 5.6.1 发行版。

perl file comparison
3个回答
33
投票

它在核心

use File::Compare;

if (compare("file1", "file2") == 0) {
  print "They're equal\n";
}

7
投票

您可以先执行一些 O(1) 检查来查看文件是否不同。

如果文件大小不同,那么它们显然是不同的。

stat
函数将返回文件的大小。它还将返回另一条有用的数据:索引节点号。如果这两个文件确实是同一个文件(因为两个文件传入了相同的文件名,或者因为两个名称都是同一文件的硬链接),则 inode 编号将相同。文件显然与其本身相同。除了这两项检查之外,除了直接相互比较之外,没有更好的方法来比较两个本地文件的等效性。当然,没有必要一行一行地读,如果你愿意的话,你可以分块阅读。

#!/usr/bin/perl

use strict;
use warnings;

use File::Compare ();

sub compare {
    my ($first, $second)             = @_;
    my ($first_inode, $first_size)   = (stat $first)[1, 7];
    my ($second_inode, $second_size) = (stat $second)[1, 7];

    #same file, so must be the same;
    return 0 if $first_inode == $second_inode;

    #different sizes, so must be different
    return 1 unless $first_size == $second_size;

    return File::Compare::compare @_;
}

print compare(@ARGV) ? "not the " : "", "same\n";

0
投票

File::Compare 是一个很好的解决方案,特别是因为它位于核心中,但如果您想处理/打印出任何差异,这里有一个非常简单的代码块可以做到这一点:

sub diff {
  my ($a,$b) = @_;
   
  open(my $afh, '<', $a) || return print STDERR "Couldn't open file $a for diff\n";
  open(my $bfh, '<', $b) || return print STDERR "Couldn't open file $b for diff\n";

  my $diffs = 0;
  while (!eof($afh) && !eof($bfh)) {
    my $linea = scalar <$afh>;
    my $lineb = scalar <$bfh>;
    next if $linea eq $lineb;
    $diffs += 1; 
    print "< $linea";
    print "> $lineb";
  } 

  return $diffs unless $diffs==0;
  return print STDERR "diff file $b finished before $a\n" if eof($afh) && !eof($bfh);
  return print STDERR "diff file $a finished before $b\n" if !eof($afh) && eof($bfh);

  close($afh);
  close($bfh);
  return 0;
}

如果没有差异则返回 0。很适合有效地执行类似 system('diff',$a,$b) 的操作,但不依赖于系统是否有可用的 'diff'(例如 Windows)

© www.soinside.com 2019 - 2024. All rights reserved.