关于文件:访问C中的目录

Accessing Directories in C

程序是打开一个目录并显示文件名…例如,如果有一个文件..它应该说是文件..其他目录..但是程序将所有文件显示为目录。

有人能检查一下代码有没有错误吗……thnx

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<stdio.h>
#include<dirent.h>
#define DIR_path"root/test"      
main()
 {
   DIR *dir;
   dir=opendir(DIR_PATH);
   printf("THe files inside the directory ::
"
);

  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
"
);
                     fclose(ptr);
                }
              else
                    printf("\t DIRECTORY
"
);
        }
           close(dir);
    }
    else
            printf("ERROR OPENIN DIRECTORY");

}


一个问题是目录也是一种文件类型,通常可以是fopen()ed。您想对每个文件调用lstat()来检查它是否是一个目录。这样地:

1
2
3
4
5
6
7
8
struct stat st;
lstat(dent->d_name, &st);
if(S_ISDIR(st.st_mode))
   printf("\t DIRECTORY
"
);
else
   printf("\t FILE
"
);

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


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

这是我在Linux上尝试模仿"ls"的程序。注意:转义序列颜色在Windows中不起作用,只是为了防止您担心可移植性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#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<<"
"
;
      std::cout<<normal;
     }
  }while(directory!=NULL);
  std::cout<<normal<<'
'
;
  closedir(myDirectory);
  delete[] fullpath;
  return 0;
}


假设root/test包含一个名为foo的文件。对dent=readdir(dir)的调用将dent->d_name设置为"foo"。您已经有了显示以下内容的调试输出:printf(dent->d_name)1。然后你试着用fopen打开foo,但文件实际上是root/test/foo。所以每次都会失败(除非您在当前目录中碰巧有一个名为foo的文件)。

打开正确的文件有两种方法:

  • 通过将参数连接到opendir和文件名来构造文件的全名。类似:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*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调用更改为

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

    您必须记住在保存之前的目录时,将getcwdchdir放回该目录。不建议在生产软件中使用此方法,因为可能会有一个由于权限而无法恢复到的当前目录。

Slacker已经解释了为什么不能使用fopen来测试文件是否是目录。

1顺便说一下,应该是puts(dent->d_name)或者更好的fputs(dent->d_name, stderr):如果文件名包含%的话,原来的printf调用就会中断,这对调试输出来说不是大问题,但却是个坏习惯。