int main(int argc, char *argv[])
{
if (argc != 2) {
cout << "Usage: " << argv[0] << " \n";
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
, представленный в С++, скорее всего, не поддерживает такие хеши.
При необходимости найти более качественную функцию подсчета хеша следует выбрать ту, которая работает быстро, безопасно для памяти и позволяет убедиться, что крупные файлы с разным содержимым не получат одинаковый хеш. Последнее требование, возможно, является самым важным. Если мы решим, что один файл является дубликатом другого и притом они не содержат одинаковые данные, то это может привести к потере данных после удаления одного из них.
Существуют более качественные алгоритмы хеширования, например MD5 или одна из разновидностей SHA. Чтобы получить доступ к таким функциям в нашей программе, можно использовать, скажем, криптографический API для OpenSSL.
Об авторе
Яцек Галовиц (Jacek Galowicz) получил степень магистра наук в области электротехники и вычислительной техники в Рейнско-Вестфальском техническом университете Ахена (Германия). Во время учебы он работал ассистентом, занимаясь как преподавательской, так и научной деятельностью, а также выступил соавтором нескольких научных публикаций. В то же время в качестве фрилансера Яцек создавал приложения и драйверы ядер на языках С и С++, задействованные в разных областях, таких как графическое программирование в 3D, базы данных, обмен данными по сети и моделирование физической среды. В последнее время он занимается программированием микроядерных операционных систем, предназначенных для виртуализации Intel x86 в Intel и FireEye и предъявляющих особые требования к производительности и безопасности. Яцек обожает реализации низкоуровневого ПО на современном С++ и старается обеспечить его высокую производительность, не усложняя при этом код. В последние годы он изучал чистое функциональное программирование и Haskell, что побудило его переключиться на создание обобщенного кода с помощью метапрограммирования.
Написание книги и в то же самое время основание компании — это интересный опыт, мне даже понравилось. Последнее, однако, оказалось возможно только благодаря поддержке и терпению моей замечательной подруги Виктории (Viktoria), моих коллег и всех моих друзей. Особую благодарность выражаю Арне Мерцу (Arne Mertz) за его бесценные замечания, а также Торстену Робицки (Torsten Robitzki) и Оливеру Брансу (Oliver Bruns) из пользовательской группы C++ Ганновера за обратную связь.
О рецензенте
Арне Мерц (Arne Mertz) — специалист по C++ с более чем десятилетним опытом. Он изучал физику в Гамбургском университете (Германия), а затем стал разработчиком ПО. В основном он работал с финансовыми приложениями, написанными на С++. Арне работает в компании Zu..hlke Engineering в Германии. Кроме того, он широко известен в кругах программистов благодаря своему блогу Simplify C++! (https://arne-mertz.de), посвященному написанию чистого и удобного в сопровождении кода на C++.
Предыдущая
Стр. 119 из 119