cout << "Usage: " << argv[0] << "
return 1;
}
path dir {argv[1]};
if (!exists(dir)) {
cout << "Path " << dir << " does not exist.\n";
return 1;
}
8. Единственное, что нам осталось сделать, — вызвать функцию reduce_dupes
для этого каталога и вывести на экран информацию о том, сколько файлов мы удалили:
const size_t dupes {reduce_dupes(dir)};
cout << "Removed " << dupes << " duplicates.\n";
}
9. Компиляция и запуск программу, для примера каталога, содержащего дубликаты, выглядит следующим образом. Я использовал инструмент du
, чтобы проверить размер каталога до и после запуска нашей программы, с целью продемонстрировать работоспособность нашего подхода:
$ du -sh dupe_dir
1.1M dupe_dir
$ ./dupe_compress dupe_dir
Removed dupe_dir/dir2/bar.jpg because it is a duplicate of
dupe_dir/dir1/bar.jpg
Removed dupe_dir/dir2/base10.png because it is a duplicate of
dupe_dir/dir1/base10.png
Removed dupe_dir/dir2/baz.jpeg because it is a duplicate of
dupe_dir/dir1/baz.jpeg
Removed dupe_dir/dir2/feed_fish.jpg because it is a duplicate of
dupe_dir/dir1/feed_fish.jpg
Removed dupe_dir/dir2/foo.jpg because it is a duplicate of
dupe_dir/dir1/foo.jpg
Removed dupe_dir/dir2/fox.jpg because it is a duplicate of
dupe_dir/dir1/fox.jpg
Removed 6 duplicates.
$ du -sh dupe_dir
584K dupe_dir
Как это работает
Мы использовали функцию create_symlink
, чтобы создать входную точку в другой файл в файловой системе. Это позволит избежать наличия дубликатов. Кроме того, можно создать жесткую ссылку с помощью функции create_hard_link
. Семантически оба этих подхода похожи друг на друга, но жесткие ссылки имеют другие технические последствия, нежели мягкие. Некоторые форматы файловых систем и вовсе могут не поддерживать жесткие ссылки или, например, лишь определенное количество жестких ссылок, ссылающихся на один и тот же файл. Еще одна проблема заключается в том, что жесткие ссылки не могут указывать из одной файловой системы на другую.
Однако помимо деталей реализации существует еще один источник ошибок, проявляющийся при использовании create_symlink
или create_hard_link
. В следующих строках содержится ошибка. Можете ли вы ее заметить сразу?
path a {"some_dir/some_file.txt"};
path b {"other_dir/other_file.txt"};
remove(b);
create_symlink(a, b);
При выполнении этой программы ничего плохого не случится, но символьная ссылка будет "some_dir/some_file.txt"
, а это неверно. Проблема заключается в том, что она должна указывать либо на "/absolute/path/some_dir/some_file.txt"
, либо на "../some_dir/some_file.txt"
. Вызов create_ symlink
использует корректный абсолютный путь, если мы напишем следующий код:
create_symlink(absolute(a), b);
create_symlink
не проверяет, корректен ли путь, на который мы создаем ссылку.
Дополнительная информация
Как можно заметить, наша функция определения хеша довольно незамысловата. Мы реализовали ее такой, чтобы пример оставался простым и не имел внешних зависимостей.
В чем заключается проблема нашей хеш-функции? На самом деле есть даже две проблемы.
1. Мы считываем в строку весь файл. Это будет иметь катастрофические последствия для файлов, которые крупнее нашей системной памяти.
2. Типаж хеш-функции hash
, представленный в С++, скорее всего, не поддерживает такие хеши.
При необходимости найти более качественную функцию подсчета хеша следует выбрать ту, которая работает быстро, безопасно для памяти и позволяет убедиться, что крупные файлы с разным содержимым не получат одинаковый хеш. Последнее требование, возможно, является самым важным. Если мы решим, что один файл является дубликатом другого и притом они не содержат одинаковые данные, то это может привести к