11

我正在制作一个在 Linux shell 中运行的程序,它接受一个参数(一个目录),并显示目录中的所有文件及其类型。

输出应该是这样的:

 << ./Program testDirectory

 Dir directory1
 lnk linkprogram.c
 reg file.txt

如果没有参数,它使用当前目录。这是我的代码:

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>

int main(int argc, char *argv[])
{
  struct stat info;
  DIR *dirp;
  struct dirent* dent;

  //If no args
  if (argc == 1)
  {

    argv[1] = ".";
    dirp = opendir(argv[1]); // specify directory here: "." is the "current directory"
    do
    {
      dent = readdir(dirp);
      if (dent)
      {
        printf("%c ", dent->d_type);
        printf("%s \n", dent->d_name);

        /* if (!stat(dent->d_name, &info))
         {
         //printf("%u bytes\n", (unsigned int)info.st_size);

         }*/
      }
    } while (dent);
    closedir(dirp);

  }

  //If specified directory 
  if (argc > 1)
  {
    dirp = opendir(argv[1]); // specify directory here: "." is the "current directory"
    do
    {
      dent = readdir(dirp);
      if (dent)
      {
        printf("%c ", dent->d_type);
        printf("%s \n", dent->d_name);
        /*  if (!stat(dent->d_name, &info))
         {
         printf("%u bytes\n", (unsigned int)info.st_size);
         }*/
      }
    } while (dent);
    closedir(dirp);

  }
  return 0;
}

由于某种原因dent->d_type没有显示文件的类型。我真的不知道该怎么做,有什么建议吗?

4

4 回答 4

26

d_type是一种速度优化,可在支持时节省lstat(2)通话费用。

正如readdir(3) 手册页指出的那样,并非所有文件系统都在该d_type字段中返回真实信息(通常是因为读取 inode 需要额外的磁盘寻道,如果您不使用 XFS 就是这种情况(mkfs.xfs -n ftype=1暗示-m crc=1还不是默认值)。总是设置的文件系统DT_UNKNOWN在现实生活中很常见,不是你可以忽略的。XFS 不是唯一的例子。

你总是需要使用lstat(2) if的代码d_type==DT_UNKNOWN,如果单独的文件名不足以决定它是无趣的。(对于一些调用者来说就是这种情况,例如find -name或扩展 glob *.c,这就是为什么readdir如果需要额外的磁盘读取就不会产生填充它的开销。)

Linuxgetdents(2)手册页有一个示例程序,可以执行您正在尝试执行的操作,包括将d_type字段解码为文本字符串的链式三元运算符块。(正如其他答案指出的那样,您的错误是将其作为字符打印出来,而不是将其与DT_REG,DT_DIR等进行比较。)

无论如何,其他答案主要涵盖了一些事情,但错过了关键细节,即您需要在以下情况下进行回退d_type == DT_UNKNOWN(Linux 上的 0。 d_type存储在过去的填充字节中,直到 Linux 2.6.4)。

为了便于移植,你的代码需要检查是否有struct dirent一个d_type字段,如果你使用它,或者你的代码甚至不能在 GNU 和 BSD 系统之外编译。(见readdir(3)


我写了一个使用 readdir 查找目录的示例,使用d_typestat退到 d_type 在编译时不可用时,当它是 DT_UNKNOWN 时,以及符号链接。

于 2015-03-17T08:40:40.243 回答
5

返回结构中的d_type给出类型的数字。您不能直接打印它,因为使用的值在解释为 ASCII 时是不可打印的(例如,对于 dirs,它们是 4,对于文件是 8。)。

您可以将它们打印为这样的数字:

printf("%d ", dent->d_type)

或者将它们与常量进行比较,并从中DT_DIR构造一些有意义的输出,例如 char 类型:

if(dent->type == DT_DIR) type = 'd'
于 2014-05-30T15:45:51.950 回答
3

像这样打印d_type为整数:

printf("%d ", dent->d_type);

你会看到有意义的值。

于 2014-05-30T15:38:11.310 回答
1

我能够在 ubuntu 上使用 d_type:

    switch (readDir->d_type)
    {
    case DT_DIR:
        printf("Dir: %s\n", readDir->d_name);
        break;
    case DT_REG:
        printf("File: %s\n", readDir->d_name);
        break;
    default:
        printf("Other: %s\n", readDir->d_name);
    }

条目类型列表可以在 dirent.h 中找到(这对于 ubuntu 以外的操作系统可能有所不同):

dirent.h

#define DT_UNKNOWN       0
#define DT_FIFO          1
#define DT_CHR           2
#define DT_DIR           4
#define DT_BLK           6
#define DT_REG           8
#define DT_LNK          10
#define DT_SOCK         12
#define DT_WHT          14
于 2020-08-05T13:27:39.727 回答