Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.149.23.12] |
|
Сообщ.
#1
,
|
|
|
Очень часто в форуме возникают вопросы про создание директорий.
Штука достаточно простая, большинство бы и так догадалось как делать, но иногда нужно просто держать сухим нужный кусок кода, вынуть его из заначки и применить. Расскажу – как нужно делать. Нужно воспользоваться API-шной функцией CreateDirectory. Функция – повторюсь, из WinAPI, в MFC ничего подобного нет. Несколько раз видел в ответ на скупой и лаконичный ответ “CreateDirectory” вопрос “Это у какого класса такой метод?”. Вопрос подобный повергает меня в смущение, но это уже оффтопик. А теперь рассмотрим очень часто встречающуюся ситуацию, когда при создании директории “C:\\1\\2\\3\\4” в момент попытки создания не существует ни директории 1, ни 2, ни 3, ни 4. В общем – создать её в этом случае одним вызовом CreateDirectory() не удастся. Тогда можно воспользоваться обещаным куском кода. Данный код не привязан к Visual C++ или, например, lcc (на котором он и был написан), и вообще к С++ (на Дельфи ситуация будет выглядеть очень похоже, сдецл поменияется только синтаксис). TCHAR sPathTo [] = “c:\\1\\2\\3\\4\\5\\6\\7\\8”;//директория, которую нужно создать bool AQLCreateDirectory(TCHAR * sPathTo) { //пока директория не создана, будем пытаться её создать// while(CreateDirectory(sPathTo, NULL) == FALSE) { /* директория не создана, поэтому нужно сначала создать ”предыдущую” директорию */ TCHAR sTemp[MAX_PATH]; int k = strlen(sPathTo); strcpy(sTemp, sPathTo); //пытаемся найти и создать директорию самого “нижнего” уровня while(CreateDirectory(sTemp, NULL) != TRUE) { /* пытаемся найти первичные половые признаки предыдущей директории.... */ while(szTemp1[--k] != '\\') { if(k<=1) return FALSE;/* похоже, что директория создана быть вообще не может! sTemp[k] = NULL; } /* ......а как только нашли - создать её */ } //во время первого прохода будет создана директория “1”, во время второго – “2” и т.д. } return TRUE; } В общем, код достаточно простой, и ясен почти без комментариев. Более того: его можно изменить. Например: разобрать один раз строку с исходным путём, и потом создать подряд все директории, начиная с первой (может уменьшиться время потраченое на разбор строки), но могу сказать, почему я этого не сделал. Если не хватает 1-ой 2-х директорий в самом конце пути (наиболее часто встречающаяся ситуация), то код будет работать не намного дольше, а может и вообще быстрее (если вложенность большая). Причин, по которым директория не может быть создана может быть много, например - у пользователя не хватает прав. В этом случае код можно расширять и дополнять. |
Сообщ.
#2
,
|
|
|
Цитата AQL @ 29.02.04, 14:25 Несколько раз видел в ответ на скупой и лаконичный ответ “CreateDirectory” вопрос “Это у какого класса такой метод?”. Вопрос подобный повергает меня в смущение, но это уже оффтопик. Странно, неужели и так нельзя понять, что это API функция. Мне б и ничего другого в голову не пришло при прочтении такого ответа, кроме как то, что это API. Функция конечно нужная, но, помоему, человек, которому она могла понадобиться и сам бы написал ее А в Delphi, помоему такая функция реализована... Я точно не знаю, но уже видел топик с такой темой, и там человек, которому эта ф-я понадобилась писал, что в Delphi она есть. А вообще эту тему можно добавить в ФАК, помоему -достойна. |
Сообщ.
#3
,
|
|
|
Функция стопудово нужная. А то, что функция API-шная доходит далеко не сразу и далеко не до всех.
(кстати - в Дельфях она кажись и вправду уже есть, но у нас то С++, все делаем ручками). |
Сообщ.
#4
,
|
|
|
Цитата AQL, 29.02.04, 18:47 кстати - в Дельфях она кажись и вправду уже есть Ага: function ForceDirectories(const Dir: string): Boolean; ЗЫ. Я в принципе согласен с kipelov, "любой" человек напишет эту функцию, если ему она понадобится, но человек щас ленивый пошёл, так что думаю она будет востребованна... |
Сообщ.
#5
,
|
|
|
В приведенной функции есть недочет - она не создаст директорию "C:/Temp/1/2/3", хотя в принципе такой формат задания имени допустИм.
|
Сообщ.
#6
,
|
|
|
Да AQL, я согласен с Дядей...и он там был не один
Я те тут подправил.... BOOL AQLCreateDirectory( LPCTSTR sPathTo) { BOOL bRet = sPathTo ? TRUE : FALSE; //пока директория не создана, будем пытаться её создать while( bRet && (bRet = CreateDirectory(sPathTo, NULL)) == FALSE) { // директория не создана, поэтому нужно сначала создать ”предыдущую” директорию __try { int k = lstrlen( sPathTo); if( k >= MAX_PATH) break; // Слишком длинное имя.... LPTSTR sTemp = LPTSTR( _alloca( (k + 1) * sizeof(TCHAR))); // Экономия стека :) lstrcpy( sTemp, sPathTo); while( k && sTemp[ k] != TCHAR('\\') && sTemp[ k] != TCHAR('/')) --k; if( k <= 0) break; // похоже, что директория создана быть вообще не может! sTemp[ k] = TCHAR( '\0'); bRet = AQLCreateDirectory( sTemp); } __except( GetExceptionCode() == STATUS_STACK_OVERFLOW) { break; } } return bRet; } Тестировал: int _tmain(int argc, _TCHAR* argv[]) { BOOL bRet; bRet = AQLCreateDirectory( NULL); // Error creating bRet = AQLCreateDirectory( "\\"); // Error creating bRet = AQLCreateDirectory( ""); // Error creating bRet = AQLCreateDirectory( "C:\\"); // Error creating bRet = AQLCreateDirectory( ":"); // Error creating bRet = AQLCreateDirectory( "1"); // Succesfull bRet = AQLCreateDirectory( "1\\2\\3\\4\\5\\6"); // Succesfull bRet = AQLCreateDirectory( "\\1\\2\\3\\4\\5\\6"); // Succesfull bRet = AQLCreateDirectory( "C:\\1\\2\\3\\4\\5\\6"); // Succesfull bRet = AQLCreateDirectory( "C:/1/2/3/4/5/6"); // Succesfull return 0; } Мож кто-то ещё чего натестит.... |
Сообщ.
#7
,
|
|
|
2Lucifer>> MSDN about MakeSureDirectoryPathExists:
Цитата Requirements Client: Included in Windows XP and Windows 2000 Professional. |
Сообщ.
#8
,
|
|
|
В UNIX-like директория создается вызовом
Цитата int mkdir(const char *pathname, mode_t mode); mode - права доступа. Просмотр директории Цитата #include <sys/types.h> #include <dirent.h> char * path = "path"; DIR *dir = opendir(path); dirent *dirp; while ( (dirp = readdir(dir)) != NULL ) { // Печать всех содержащихся в path файлов и директорий printf ("%s\n", dirp->d_name); } closedir (dir); |
Сообщ.
#9
,
|
|
|
Спасибо за дополнения
(про рекурсии - не люблю я их, поэтому и не использовал). |
Сообщ.
#10
,
|
|
|
Поиск путей по шаблону (для UNIX-like)
man glob Например для поиска файлов типа "../*.[c,h]": #include <glob.h> glob_t globbuf; if ( !!glob("../*.[c,h]", 0, NULL, &globbuf) ) { // Ищем printf ("ERROR\n"); return -1; } for (int i = 0; i < globbuf.gl_pathc; i++) { // Читаем все пути printf ("\t%s\n", globbuf.gl_pathv[i]); // Выводим } Вывод будет аналогичным выводу ls ../*.[c,h] |