Разработка

Будущая программа будет состоять из определения процедуры compareFiles и её вызова, дополненного проверкой правильности параметров командной строки:

sub compareFiles($$;$)
{
	
}

if(@ARGV==2)
{
	print "Файлы «$ARGV[0]» и «$ARGV[1]» различаются\n"
		if compareFiles($ARGV[0], $ARGV[1]);
}
else
{
	warn "$0: Требуется ровно два параметра в командной строке\n";
}

Приступим к кодированию процедуры compareFiles. Первое, что нужно сделать, это, как обычно, поместить в переменные первые два параметра — имена файлов:

my $name1=shift;
my $name2=shift;

Третий параметр — размер буфера чтения — сделаем факультативным (необязательным). Это означает, что если при вызове процедуры он не передан, будет использовано значение по умолчанию, 512 байт. Появившийся сравнительно недавно в языке Perl оператор // позволит нам очень лаконично обработать необязательный параметр:

my $bufferSize=shift // 512;

Значением выражения $a//$b будет $a, если $a определено, и $b в противном случае. В старых версиях Perl такой код не заработает, и его следует заменить на что-то вроде

my $bufferSize=shift;
$bufferSize=512 unless defined $bufferSize;

Далее пытаемся открыть оба файла для чтения. В случае неудачи хотя бы с одним из файлов сообщаем об ошибке и возвращаем неопределённое значение как признак ошибки:

unless(open $file1, '<', $name1)
{
	warn "$0: Невозможно открыть «$name1»: $!\n";
	return;
}
unless(open $file2, '<', $name2)
{
	warn "$0: Невозможно открыть «$name2»: $!\n";
	close $file1 or warn "$0: Невозможно закрыть «$name1»: $!";
	return;
}

Если попытки открытия файлов увенчались успехом, из файлов можно читать. В бесконечном цикле происходит считывание в два буфера, $buffer1 и $buffer2, очередных порций файлов. Перед началом цикла мы предполагаем, что файлы совпадают, о чём свидетельствует начальное нулевое значение переменной $result. Впрочем, эта переменная может изменить своё значение на единичное, как только два только что прочитанных блока окажутся различными, либо на неопределённое, чуть только произойдёт ошибка чтения. В обоих случаях дальнейшее чтение продолжать бессмысленно, и цикл нужно покинуть. Впрочем, ситуация, когда из обоих файлов прочитано 0 байт, это также повод покинуть цикл; в этом случае оба файла дочитаны до конца и различий в них не обнаружено, а переменная $result сохранила своё нулевое значение, что нас вполне устроит.

my($buffer1, $buffer2);
my $result=0;
while()
{
	my $n1=read $file1, $buffer1, $bufferSize;
	unless(defined $n1)
	{
		warn "$0: Невозможно прочитать «$name1»: $!\n";
		undef $result;
		last;
	}
	my $n2=read $file2, $buffer2, $bufferSize;
	unless(defined $n2)
	{
		warn "$0: Невозможно прочитать «$name2»: $!\n";
		undef $result;
		last;
	}
	last unless $n1 or $n2;	выход из цикла, если оба файла дочитаны до конца
	if($buffer1 ne $buffer2)
	{
		$result=1;
		last;
	}
}

По окончании цикла пытаемся закрыть файлы, предупреждая об ошибке закрытия:

close $file2 or warn "$0: Невозможно закрыть «$name2»: $!";
close $file1 or warn "$0: Невозможно закрыть «$name1»: $!";
return $result;

Отличительной особенностью получившейся программы является параноидальный контроль за ошибками открытия, чтения и закрытия файлов.

Информатика-54© А. Н. Швец