Доступ к каталогам в C

Программа должна открыть каталог и отобразить имя файлов... т. е. если есть файл... он должен сказать ФАЙЛ... иначе КАТАЛОГ... но программа отображает все файлы как каталог...

Может ли кто-нибудь проверить код на наличие ошибок....thnx

#include<stdio.h>
#include<dirent.h>
#define DIR_path "root/test"      
main()
 {
   DIR *dir;
   dir=opendir(DIR_PATH);
   printf("THe files inside the directory :: \n");

  struct dirent *dent;
  if(dir!=NULL)
   {

       while((dent=readdir(dir)))
         {
            FILE *ptr;
            printf(dent->d_name);

              if(ptr=fopen(dent->d_name,"r"))
                {
                     print("\tFILE\n");
                     fclose(ptr);
                }
              else
                    printf("\t DIRECTORY\n");
        }
           close(dir);
    }
    else
            printf("ERROR OPENIN DIRECTORY");

}

person Vinod K    schedule 21.08.2010    source источник
comment
Возможный обман stackoverflow.com/questions/1542763/, stackoverflow.com/questions/3029633/ и/или stackoverflow.com/questions/1271064/. Кстати, это самое уродливое использование дирента, которое я когда-либо видел. Смотрите ссылки, почему.   -  person rubenvb    schedule 21.08.2010


Ответы (3)


Одна проблема заключается в том, что каталог также является типом файла и обычно может быть fopen()ed. Вы хотите вызвать lstat() для каждого файла, чтобы проверить, является ли он каталогом. Нравится:

struct stat st;
lstat(dent->d_name, &st);
if(S_ISDIR(st.st_mode))
   printf("\t DIRECTORY\n");
else
   printf("\t FILE\n");

Но эта ошибка должна привести к тому, что все записи будут отображаться в виде файлов. У вас есть права на чтение файлов в этом каталоге? Каково значение errno после вызова fopen()?

person slacker    schedule 21.08.2010
comment
На самом деле вы, вероятно, захотите проверить код возврата lstat() на наличие ошибок. В цикле readdir() это маловероятно, но возможно. - person NVRAM; 02.10.2010

Предположим, что root/test содержит файл с именем foo. Вызов dent=readdir(dir) устанавливает dent->d_name в "foo". У вас уже есть выходные данные отладки, которые показывают следующее: printf(dent->d_name)¹. Затем вы пытаетесь открыть foo с помощью fopen, но на самом деле это файл root/test/foo. Так что это каждый раз терпит неудачу (если только у вас нет файла с именем foo в текущем каталоге).

Есть два способа открыть нужный файл:

  • Создайте полное имя файла, соединив аргумент opendir с именем файла. Что-то типа:

    /*before */
    size_t dir_length = strlen(DIR_PATH);
    char *filename = malloc(dir_length + NAME_MAX + 2); /*error checking omitted*/
    strcpy(filename, DIR_PATH);
    filename[dir_length] = '/';
    filename[dir_length+1] = 0;
    while ((dent = readdir(dir)) != NULL) {
        strcpy(filename + dir_length + 1, dent->d_name);
        /*now call lstat, fopen, etc. on filename*/
    
  • Перейдите в каталог, который вы перечисляете. Например, измените вызов opendir на

    chdir(DIR_PATH); /*error checking omitted*/
    dir = opendir(".");
    

    Вы должны не забыть сохранить предыдущий каталог с getcwd и chdir обратно в него впоследствии. Этот метод не рекомендуется для производственного программного обеспечения, потому что существует возможность иметь текущий каталог, в который вы не можете chdir вернуться из-за разрешений.

бездельник уже объяснил, почему fopen нельзя использовать для проверки того, является ли файл каталогом.

¹, который, кстати, должен быть puts(dent->d_name) или даже лучше fputs(dent->d_name, stderr): ваш исходный вызов printf прервется, если имя файла содержит %, что не является большой проблемой для отладки вывода, но является плохой привычкой.

person Gilles 'SO- stop being evil'    schedule 21.08.2010

это комбинация двух ответов бездельника и Жиля. используйте lstat, но не используйте его, как сказал бездельник. Вам нужно отправить lstat полный путь, а не просто dent->d_name. И просто чтобы вы знали, что lstat требует, чтобы вы включили sys/stat.h>
если вы посмотрите на справочную страницу для lstat, внизу есть тестовая программа, или просто посмотрите на мою.

Вот моя программа, которая пытается имитировать «ls» в Linux. Примечание: цвета управляющей последовательности не работают в Windows на тот случай, если вы беспокоитесь о переносимости.

#include <iostream>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

int main(int argc,char* argv[]){
 char blue[] = { 0x1b, '[', '1', ';', '3', '4', 'm', 0 };
 char normal[]={ 0x1b, '[', '0', ';', '3', '9', 'm', 0 };
 char green[]= { 0x1b, '[', '0', ';', '3', '2', 'm', 0 };
 char red[]=   { 0x1b, '[', '0', ';', '3', '1', 'm', 0 };
 char cyan[]=  { 0x1b, '[', '0', ';', '3', '6', 'm', 0 };
 DIR* myDirectory;
 char *path=NULL;
 size_t size=100;
 int result;
 char* fullpath;
 if (argc >=3){
   std::cout<<"Usage: myls <path>"<<std::endl;
   return -1;
 }
 if (argc >= 2){
   myDirectory=opendir(argv[1]);
   if (errno==ENOENT){
   std::cout<<"error: file does not exist"<<std::endl;
   return -1;
   }
   path=argv[1];
 if (path[strlen(path)-1]!='/')
strcat(path,"/");
 }
 else if(argc==1){
   path=getcwd(path,size);
   strcat(path,"/");
   myDirectory=opendir(path);
 }
 struct stat fileProperties;
 struct dirent* directory;
 do{
    directory=readdir(myDirectory);
    if (directory!=NULL){
    fullpath=new char[strlen(path)+strlen(directory->d_name)+2];
    strcat(fullpath,path);
    strcat(fullpath,directory->d_name);
    result=lstat(fullpath,&fileProperties);
    //std::cout<<result<<fullpath;
    switch (fileProperties.st_mode & S_IFMT){
      case S_IFDIR: std::cout<<blue;
            break;
      case S_IFLNK: std::cout<<cyan; break;
      case S_IFREG: std::cout<<normal;
      default:  std::cout<<normal;
        if (fileProperties.st_mode & S_IXUSR)
            std::cout<<green;
        break;
      }

      std::cout<<directory->d_name<<"\n";
      std::cout<<normal;
     }
  }while(directory!=NULL);
  std::cout<<normal<<'\n';
  closedir(myDirectory);
  delete[] fullpath;
  return 0;
}
person Craig    schedule 30.03.2012