【问题标题】:Accessing Directories in C在 C 中访问目录
【发布时间】:2011-04-01 23:53:11
【问题描述】:

程序是打开一个目录并显示文件名... 即如果有一个文件..它应该说 FILE..else DIRECTORY.. 但是程序将所有文件显示为目录..

有人可以检查代码是否有任何错误....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");

}

【问题讨论】:

标签: c file directory opendir dirent.h


【解决方案1】:

一个问题是目录也是一种文件,一般可以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");

但是这个错误应该导致所有条目都显示为文件。您对该目录中的文件有读取权限吗? fopen() 调用后errno 的值是多少?

【讨论】:

  • 实际上,您可能想检查 lstat() 的返回码是否有错误。在 readdir() 循环中,这不太可能,但可能。
【解决方案2】:

假设root/test 包含一个名为foo 的文件。对dent=readdir(dir) 的调用将dent-&gt;d_name 设置为"foo"。您已经有调试输出显示:printf(dent-&gt;d_name)¹。然后你尝试用fopen打开foo,但文件实际上是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(".");
    

    你必须记住用getcwdchdir 保存之前的目录,然后再回到它。不建议在生产软件中使用此方法,因为可能会有一个当前目录,由于权限,您无法chdir 返回。

slacker has already explained why fopen can't be used to test if a file is a directory.

¹ 顺便说一句,应该是puts(dent-&gt;d_name) 或者更好的fputs(dent-&gt;d_name, stderr):如果文件名包含%,那么你原来的printf 调用会中断,这对于调试输出来说不是一个大问题,但这是一个坏习惯进入。

【讨论】:

    【解决方案3】:

    它结合了 slacker 和 Gilles 的两个答案。使用 lstat 但不要像 slacker 说的那样使用它。您需要向 lstat 发送完整路径,而不仅仅是 dent->d_name。并且您知道 lstat 要求您包含 sys/stat.h>
    如果您查看 lstat 的手册页,底部有一个测试程序,或者只是查看我的。

    这是我试图在 linux 上模仿“ls”的程序。注意:转义序列颜色在 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;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-22
      • 1970-01-01
      • 2019-05-29
      • 2017-11-12
      • 2010-11-08
      • 2011-01-21
      • 2018-12-06
      • 2012-10-11
      • 1970-01-01
      相关资源
      最近更新 更多