Linux C 读取目录

Linux C read a directory

提问人:Kouros 提问时间:6/16/2013 更新时间:9/13/2023 访问量:3454

问:

您好,我想读取和写入目录,就像读取和写入文件一样。我总是使用 、 和 函数,这意味着我使用描述符。但是在目录上执行此操作不起作用,调用有效,但返回 -1 并且是 EISDIR。我是否被迫使用流来读取目录?openreadwritecloseopenreaderrno

C Linux 目录

评论


答:

0赞 markmb 6/16/2013 #1

我在Stack Overflow(如何使用C或C++获取目录中的文件列表?)中找到了这段代码,这对我理解它的工作原理有很大帮助:

#include <dirent.h>
#include <stdio.h>
#include <string.h>

int main(){
    DIR* dirFile = opendir( "." );
    struct dirent* hFile;
    if ( dirFile ) 
    {
    while (( hFile = readdir( dirFile )) != NULL ) 
    {
       if ( !strcmp( hFile->d_name, "."  )) continue;
       if ( !strcmp( hFile->d_name, ".." )) continue;

     // in linux hidden files all start with '.'
       if ( gIgnoreHidden && ( hFile->d_name[0] == '.' )) continue;

     // dirFile.name is the name of the file. Do whatever string comparison 
     // you want here. Something like:
        if ( strstr( hFile->d_name, ".c" ))
           printf( "found an .txt file: %s", hFile->d_name );
    } 
  closedir( dirFile );
 }
}
3赞 caf 6/16/2013 #2

不能在目录上使用 and 系统调用。相反,/ 系统调用用于读取目录。根本无法直接写入目录。read()write()getdents()getdents64()

此外,glibc 没有为 / 系统调用提供包装器 - 而是提供符合 POSIX 的函数,该函数是使用这些系统调用实现的。大多数程序应该使用 ,但也可以直接使用 调用系统调用。getdents()getdents64()readdir()readdir()syscall()

1赞 Hosein Rahnama 9/13/2023 #3

正如@caf指出的,您应该用于此目的。实际上,人们使用序列 , 来读取目录文件。此外,目录是只读的,不能写入。但是,如果您对使用系统调用读取目录感到好奇,这里有一个没有错误检查的最小示例。在这里,该函数采用与目录对应的文件描述符,并在每次调用时返回一个目录条目。目录名称可以作为命令行参数传递。默认行为打印当前工作目录的内容。你可以在这里或这里阅读更多关于的信息。readdiropendirreaddirclosedirgetdentsread_direntgetdents

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/syscall.h>

#define BUF_SIZE 1024

typedef struct linux_dirent 
{
    long           d_ino;
    off_t          d_off;
    unsigned short d_reclen;
    char           d_name[];
} LinuxDirEnt;

LinuxDirEnt *read_dirent(int fd);

int main(int argc, char *argv[])
{
    int fd;
    LinuxDirEnt *d;

    fd = open(argc > 1 ? argv[1] : ".", O_RDONLY);

    printf("inode#  d_reclen  d_name\n");
    while(d = read_dirent(fd))
        printf("%8ld  %4d  %s\n", d->d_ino, d->d_reclen, d->d_name);   

    exit(EXIT_SUCCESS);
}

LinuxDirEnt *read_dirent(int fd)
{
    static int nread = 0;
    static int bpos = 0;
    static char buf[BUF_SIZE];
    static LinuxDirEnt *d;
    
    if (nread == 0)
    {
        nread = syscall(SYS_getdents, fd, buf, BUF_SIZE);
        if (nread == 0)
            return NULL;
        bpos = 0;
    }
    else
        bpos += d->d_reclen;
    d = (LinuxDirEnt *)(buf + bpos);
    nread -= d->d_reclen; 

    return d;
}