Как пройти по каталогу на C

Я использую glib в своем приложении и вижу, что в glib есть удобные оболочки для C remove, unlink и rmdir. Но они работают только с одним файлом или каталогом за раз.

Насколько я понимаю, ни стандарт C, ни glib не содержат каких-либо функций рекурсивного обхода каталогов. Я также не вижу особого способа удалить сразу все дерево каталогов, как в случае с rm -rf.

Что касается того, что я делаю, меня не беспокоят какие-либо сложности, такие как разрешения, символические ссылки для резервного копирования дерева (бесконечная рекурсия) или все, что исключает очень наивную реализацию ... поэтому я не прочь написать свой собственный функция для него.

Однако мне любопытно, есть ли эта функция где-нибудь в стандартных библиотеках gtk или glib (или в какой-либо другой легко повторно используемой библиотеке C), и я просто не наткнулся на нее. Поиск в Google по этой теме дает много ложных сведений.

В противном случае я планирую использовать такой алгоритм:

dir_walk(char* path, void* callback(char*) {
  if(is_dir(path) && has_entries(path)) {
    entries = get_entries(path);
    for(entry in intries) { dir_walk(entry, callback); }
  }
  else { callback(path) }
}

dir_walk("/home/user/trash", remove);

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


person mlibby    schedule 07.02.2010    source источник
comment
технически только remove() входит в стандарт C, остальные 2 - в POSIX :)   -  person Matt Joiner    schedule 07.02.2010
comment
В дополнение к существующим ответам, обратите внимание, что нельзя просто пройти каталог в Мордор, будь то на C или на любом другом языке.   -  person Error 454    schedule 07.07.2012
comment
В дополнение к существующим ответам я хотел бы указать, что надежный код не должен использовать рекурсию. Вместо этого используйте итерацию и стек.   -  person LRN    schedule 10.01.2016


Ответы (5)


Вы можете использовать GFileEnumerator, если хотите сделать это с помощью glib.

person AndiDog    schedule 07.02.2010
comment
Является ли GFileEnumerator рекурсивным? Я читал документацию, но в ней ничего не сказано. Конечно, я могу попробовать и узнать ... - person mlibby; 07.02.2010
comment
Нет, это не так. Доступно несколько руководств, но вам следует взглянуть на gezeiten. org / post / 2009/04 / Writing-Your-Own-GIO-Jobs, который показывает рекурсивный список файлов (поиск по g_file_deep_count). - person AndiDog; 07.02.2010

Вы смотрели <dirent.h>? AFAIK это относится к спецификации POSIX, которая должна быть частью стандартной библиотеки большинства, если не всех компиляторов C. См., Например, этот <dirent.h> справочник (Единая спецификация UNIX версии 2 автора Открытая группа).

P.S., прежде чем кто-то прокомментирует это: нет, это не предлагает рекурсивный обход каталога. Но я думаю, что лучше всего это реализует разработчик; требования могут сильно различаться, поэтому универсальная рекурсивная функция обхода должна быть очень мощной. (Например: отслеживаются ли символические ссылки? Следует ли ограничивать глубину рекурсии? И т. Д.)

person stakx - no longer contributing    schedule 07.02.2010
comment
В окнах это opendir / closedir и тому подобное. Или FindFirstFile FindNextFile. - person Ronny Brendel; 29.03.2010

Некоторые платформы включают ftw и nftw: "(новый) обход дерева файлов". Проверка страницы руководства на imac показывает, что они являются устаревшими, и новые пользователи должны предпочесть fts. Переносимость может быть проблемой при любом из этих вариантов.

person William Pursell    schedule 07.02.2010

Стандартные библиотеки C предназначены для обеспечения примитивной функциональности. Вы говорите о сложном поведении. Вы можете легко реализовать его, используя низкоуровневые функции, представленные в выбранном вами API - взгляните на это руководство.

person Hassan Syed    schedule 07.02.2010

Обратите внимание, что «удобные оболочки», которые вы упоминаете для remove (), unlink () и rmdir (), предполагая, что вы имеете в виду те, которые объявлены в ‹glib / gstdio.h›, на самом деле не являются «удобными оболочками». В чем удобство добавления к стандартным функциям префикса "g_"? (И обратите внимание, что я говорю это, даже если я впервые их представил.)

Единственная причина, по которой существуют эти оболочки, - это проблемы с именами файлов в Windows, где эти оболочки фактически состоят из реального кода; они принимают аргументы имени файла в Unicode, закодированные в UTF-8. Соответствующие "развернутые" функции библиотеки Microsoft C принимают имена файлов в системной кодовой странице.

Если вы специально не пишете код, предназначенный для переноса в Windows, нет причин использовать оболочки g_remove () и т. Д.

person tml    schedule 15.02.2010
comment
Удобство в том, что версии g_ обрабатывают обсуждаемые вами случаи. Поскольку я использую glib и gtk для многих других вещей, имеет смысл быть последовательным и использовать функции g_. Невыполнение этого требования гарантирует, что мой код не будет переносимым. Я не имел в виду, что версии g_ только вызывали стандартную библиотеку. - person mlibby; 15.02.2010