如何在c中确定linux中的目录或文件

如何在c中确定linux中的目录或文件,c,linux,C,Linux,我只想打印文件名,不打印目录名。所以,我实现了这个函数 void list_file(char* directory){ DIR *d; struct dirent *dir; d = opendir(directory); if (d) { while ((dir = readdir(d)) != NULL) { printf("%c", dir->d_name[(int)strlen(dir->d_name)]);

我只想打印文件名,不打印目录名。所以,我实现了这个函数

void list_file(char* directory){
  DIR *d;
  struct dirent *dir;
  d = opendir(directory);
  if (d)
  {
    while ((dir = readdir(d)) != NULL)
    {
        printf("%c", dir->d_name[(int)strlen(dir->d_name)]);
        if(dir->d_name[(int)strlen(dir->d_name)-2] != '/')
            printf("%s\n", dir->d_name);
    }

    closedir(d);
  }
}
我检查了目录名是否以“/”字符结尾。因此,我检查了如果名称末尾有“/”字符,不要打印该名称,但当我运行该函数时,所有字符都打印在所选目录中


您能告诉我如何检查目录名的结尾吗?

您要查找的是或其变体之一。具体查看
struct stat
st_mode
字段。您感兴趣的宏是
S\u ISDIR(x)

在下面找到您修改过的代码,该代码演示了您想要的内容:

void list_file(char* directory) {
  DIR *d;
  struct dirent *dir;
  int dir_len = strlen(directory);
  char* path = malloc(dir_len + NAME_MAX + 2); // +2, 1 for '/' and 1 for '\0'
  if(path == NULL) {
    fprintf(stderr, "malloc failed\n");
    return;
  }
  strcpy(path, directory);
  if(path[dir_len-1] != '/') {
    path[dir_len] = '/';
    dir_len++;
  }
  d = opendir(directory);
  if (d) {
    while ((dir = readdir(d)) != NULL)
    {
      struct stat buf;
      strcpy(&path[dir_len], dir->d_name);
      if(stat(path, &buf) < 0) {
        fprintf(stderr, "error\n");
      }
      else {if(!S_ISDIR(buf.st_mode)) {
          printf("%s\n", dir->d_name);
        }
      }
    }

    closedir(d);
  }
  free(path);
}

它更干净,无需使用
malloc

您正在寻找的是或其变体之一。具体查看
struct stat
st_mode
字段。您感兴趣的宏是
S\u ISDIR(x)

在下面找到您修改过的代码,该代码演示了您想要的内容:

void list_file(char* directory) {
  DIR *d;
  struct dirent *dir;
  int dir_len = strlen(directory);
  char* path = malloc(dir_len + NAME_MAX + 2); // +2, 1 for '/' and 1 for '\0'
  if(path == NULL) {
    fprintf(stderr, "malloc failed\n");
    return;
  }
  strcpy(path, directory);
  if(path[dir_len-1] != '/') {
    path[dir_len] = '/';
    dir_len++;
  }
  d = opendir(directory);
  if (d) {
    while ((dir = readdir(d)) != NULL)
    {
      struct stat buf;
      strcpy(&path[dir_len], dir->d_name);
      if(stat(path, &buf) < 0) {
        fprintf(stderr, "error\n");
      }
      else {if(!S_ISDIR(buf.st_mode)) {
          printf("%s\n", dir->d_name);
        }
      }
    }

    closedir(d);
  }
  free(path);
}

它更干净,在Linux上不需要
malloc

manreaddir

On Linux, the dirent structure is defined as follows:

       struct dirent {
           ino_t          d_ino;       /* inode number */
           off_t          d_off;       /* not an offset; see NOTES */
           unsigned short d_reclen;    /* length of this record */
           unsigned char  d_type;      /* type of file; not supported
                                          by all filesystem types */
           char           d_name[256]; /* filename */
       };
[...]
Other than Linux, the d_type field is available mainly only on BSD sys‐
tems.   This  field  makes  it possible to avoid the expense of calling
lstat(2) if further actions depend on the type of  the  file.   If  the
_BSD_SOURCE  feature test macro is defined, then glibc defines the fol‐
lowing macro constants for the value returned in d_type:

   DT_BLK      This is a block device.

   DT_CHR      This is a character device.

   DT_DIR      This is a directory.

   DT_FIFO     This is a named pipe (FIFO).

   DT_LNK      This is a symbolic link.

   DT_REG      This is a regular file.

   DT_SOCK     This is a UNIX domain socket.

   DT_UNKNOWN  The file type is unknown.

man readdir
在Linux上:

On Linux, the dirent structure is defined as follows:

       struct dirent {
           ino_t          d_ino;       /* inode number */
           off_t          d_off;       /* not an offset; see NOTES */
           unsigned short d_reclen;    /* length of this record */
           unsigned char  d_type;      /* type of file; not supported
                                          by all filesystem types */
           char           d_name[256]; /* filename */
       };
[...]
Other than Linux, the d_type field is available mainly only on BSD sys‐
tems.   This  field  makes  it possible to avoid the expense of calling
lstat(2) if further actions depend on the type of  the  file.   If  the
_BSD_SOURCE  feature test macro is defined, then glibc defines the fol‐
lowing macro constants for the value returned in d_type:

   DT_BLK      This is a block device.

   DT_CHR      This is a character device.

   DT_DIR      This is a directory.

   DT_FIFO     This is a named pipe (FIFO).

   DT_LNK      This is a symbolic link.

   DT_REG      This is a regular file.

   DT_SOCK     This is a UNIX domain socket.

   DT_UNKNOWN  The file type is unknown.

根据需要尝试使用
stat、fstat和lstat中的任何一种。这用于获取文件状态

用法:

int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
  • stat()统计路径指向的文件,并填入buf

  • lstat()与stat()相同,只是如果path是符号链接,则链接本身是stat-ed,而不是它引用的文件

  • fstat()与stat()相同,只是要统计的文件由文件描述符fd指定

  • 它们都返回一个
    stat
    结构,其中包含以下字段:

    struct stat {
                   dev_t     st_dev;     /* ID of device containing file */
                   ino_t     st_ino;     /* inode number */
                   mode_t    st_mode;    /* protection */
                   nlink_t   st_nlink;   /* number of hard links */
                   uid_t     st_uid;     /* user ID of owner */
                   gid_t     st_gid;     /* group ID of owner */
                   dev_t     st_rdev;    /* device ID (if special file) */
                   off_t     st_size;    /* total size, in bytes */
                   blksize_t st_blksize; /* blocksize for filesystem I/O */
                   blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
                   time_t    st_atime;   /* time of last access */
                   time_t    st_mtime;   /* time of last modification */
                   time_t    st_ctime;   /* time of last status change */
               };
    
    从这一点开始,请尝试:

    buf.st_mode & S_IFMT                #assuming you have defined struct stat buf;
    
    将该值与
    S_IFDIR
    进行比较,以检查它是否为目录

    有关更多信息,请参阅:
    man 2 stat


    使用
    struct stat
    也可以帮助您,因为它包含文件的许多不同信息。

    根据需要尝试使用
    stat、fstat、lstat中的任何一种。这用于获取文件状态

    用法:

    int stat(const char *path, struct stat *buf);
    int fstat(int fd, struct stat *buf);
    int lstat(const char *path, struct stat *buf);
    
  • stat()统计路径指向的文件,并填入buf

  • lstat()与stat()相同,只是如果path是符号链接,则链接本身是stat-ed,而不是它引用的文件

  • fstat()与stat()相同,只是要统计的文件由文件描述符fd指定

  • 它们都返回一个
    stat
    结构,其中包含以下字段:

    struct stat {
                   dev_t     st_dev;     /* ID of device containing file */
                   ino_t     st_ino;     /* inode number */
                   mode_t    st_mode;    /* protection */
                   nlink_t   st_nlink;   /* number of hard links */
                   uid_t     st_uid;     /* user ID of owner */
                   gid_t     st_gid;     /* group ID of owner */
                   dev_t     st_rdev;    /* device ID (if special file) */
                   off_t     st_size;    /* total size, in bytes */
                   blksize_t st_blksize; /* blocksize for filesystem I/O */
                   blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
                   time_t    st_atime;   /* time of last access */
                   time_t    st_mtime;   /* time of last modification */
                   time_t    st_ctime;   /* time of last status change */
               };
    
    从这一点开始,请尝试:

    buf.st_mode & S_IFMT                #assuming you have defined struct stat buf;
    
    将该值与
    S_IFDIR
    进行比较,以检查它是否为目录

    有关更多信息,请参阅:
    man 2 stat


    使用
    struct stat
    也可以帮助您,因为它包含文件的许多不同信息。

    如何尝试检查名称是否具有扩展名。大多数文件都会有一些扩展名,比如.pdf.c etcDirectory名称不会以斜杠结尾(而且您正在访问空终止符)。斜杠由
    ls
    命令添加(给定某些选项)。您可以尝试使用d_type字段(不会在所有系统上都起作用),也可以对名称进行lstat。d_类型应该是目录的DT_DIR。@shunya很多文件不会--“自述、复制、更改日志、作者、makefile、fstab、mtab等。”谢谢大家。我的问题是关于IS_DIR控制。我在你的帮助下解决了这个问题。祝你有愉快的一天。试试看名字是否有分机。大多数文件都会有一些扩展名,比如.pdf.c etcDirectory名称不会以斜杠结尾(而且您正在访问空终止符)。斜杠由
    ls
    命令添加(给定某些选项)。您可以尝试使用d_type字段(不会在所有系统上都起作用),也可以对名称进行lstat。d_类型应该是目录的DT_DIR。@shunya很多文件不会--“自述、复制、更改日志、作者、makefile、fstab、mtab等。”谢谢大家。我的问题是关于IS_DIR控制。我在你的帮助下解决了这个问题。祝你有愉快的一天。除非
    目录
    是“.”-当前目录,否则这将不起作用。根据,struct dirent的
    d_name
    成员只是基本文件名,而不是包含前面目录的整个路径-它只是“filename”,而不是“/full/path/to/filename”。感谢您的帮助,我已经修复了创建完整路径的代码。这确实让Linux添加
    d_type
    字段的原因变得非常明显,不是吗?@AndrewHenle:好吧,如果您已经获得了目录的文件描述符,您可以
    fstatat()
    ,这对您的工作更方便。@esm非常感谢您。我在你的帮助下解决了我的问题。祝你有愉快的一天。除非
    目录
    是“.”-当前目录,否则这将不起作用。根据,struct dirent的
    d_name
    成员只是基本文件名,而不是包含前面目录的整个路径-它只是“filename”,而不是“/full/path/to/filename”。感谢您的帮助,我已经修复了创建完整路径的代码。这确实让Linux添加
    d_type
    字段的原因变得非常明显,不是吗?@AndrewHenle:好吧,如果您已经获得了目录的文件描述符,您可以
    fstatat()
    ,这对您的工作更方便。@esm非常感谢您。我在你的帮助下解决了我的问题。祝您有个美好的一天。