Будущая программа будет состоять из определения процедуры
compareFiles
и её вызова, дополненного проверкой
правильности параметров командной строки:
Perlsub compareFiles($$;$) { … } if(@ARGV==2) { print "Файлы «$ARGV[0]» и «$ARGV[1]» различаются\n" if compareFiles($ARGV[0], $ARGV[1]); } else { warn "$0: Требуется ровно два параметра в командной строке\n"; }
Приступим к кодированию процедуры compareFiles
. Первое,
что нужно сделать, это, как обычно, поместить в переменные первые два
параметра — имена файлов:
Perlmy $name1=shift; my $name2=shift;
Третий параметр — размер буфера чтения — сделаем факультативным (необязательным). Это означает, что если при вызове процедуры он не передан, будет использовано значение по умолчанию, 512 байт. Появившийся сравнительно недавно в языке Perl оператор // позволит нам очень лаконично обработать необязательный параметр:
Perlmy $bufferSize=shift // 512;
Значением выражения
будет $a
//$b
, если
$a
определено, и
$a
в противном случае. В старых
версиях Perl такой код не заработает, и его следует заменить на что-то вроде
$b
Perlmy $bufferSize=shift; $bufferSize=512 unless defined $bufferSize;
Далее пытаемся открыть оба файла для чтения. В случае неудачи хотя бы с одним из файлов сообщаем об ошибке и возвращаем неопределённое значение как признак ошибки:
Perlunless(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
сохранила своё нулевое
значение, что нас вполне устроит.
Perlmy($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; } }
По окончании цикла пытаемся закрыть файлы, предупреждая об ошибке закрытия:
Perlclose $file2 or warn "$0: Невозможно закрыть «$name2»: $!"; close $file1 or warn "$0: Невозможно закрыть «$name1»: $!"; return $result;
Отличительной особенностью получившейся программы является параноидальный контроль за ошибками открытия, чтения и закрытия файлов.