简体   繁体   中英

how to determine directory or file in linux in c

I want to print only file names without printing Directory Names. So, I implement this function

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);
  }
}

I checked that Directory names ends with '/' character. So, I checked that if there are '/' character at the end of name, don't print that name but when I run the function, all of them is printed in selected directory?

Can you lead me that how can I check the end of Directory name?

What you are looking for is stat or one of its variants. Specifically look at the st_mode field of struct stat . The macro you are interested in is S_ISDIR(x) .

Find below your modified code that demonstrates what you want:

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);
}

I have removed your first print as it was printing the null terminating character of the string.

Update:

As pointed out in the comments since we are dealing with Linux you can use the d_type field in struct dirent (which is not part of POSIX but is part of Linux ).

With that said the code would be the following.

void list_file(char* directory){
  DIR *d;
  struct dirent *dir;

  d = opendir(directory);
  if (d) {
    while ((dir = readdir(d)) != NULL)
    {
      struct stat buf;
      if(dir->d_type == DT_DIR) {
         printf("%s\n", dir->d_name);
      }
    }

    closedir(d);
  }
}

It is a lot cleaner, no need for malloc .

man readdir on 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.

Try using either of stat, fstat, lstat as required. This is used to get the file status.

Usage:

int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
  1. stat() stats the file pointed to by path and fills in buf.

  2. lstat() is identical to stat(), except that if path is a symbolic link, then the link itself is stat-ed, not the file that it refers to.

  3. fstat() is identical to stat(), except that the file to be stat-ed is specified by the file descriptor fd.

All of them return a stat structure, which contains the following fields:

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 */
           };

From this try doing:

buf.st_mode & S_IFMT                #assuming you have defined struct stat buf;

Compare the value with S_IFDIR to check if it is a directory.

For more refer to : man 2 stat

Using the struct stat can also help you because it contains many different information of a file.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM