C语言遍历文件目录:readdir,opendir

本文深入讲解了Linux系统中目录操作的三个核心函数:opendir用于打开目录,readdir用于读取目录内容,stat用于获取文件详细信息。通过示例代码展示了如何结合这三个函数遍历目录并获取文件属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

环境:Linux系统

头文件:

#include<sys/types.h>
#include<dirent.h>

一、opendir

原型

DIR* opendir (const char * path );

参数与功能

path为目录路径,打开一个目录,在失败的时候返回一个空的指针。

返回值

DIR*,DIR结构体类似于FILE,是一个内部结构,以下几个函数用这个内部结构保存当前正在被读取的目录的有关信息,其内容如下:

struct __dirstream   
{   
    void *__fd;    
    char *__data;    
    int __entry_data;    
    char *__ptr;    
    int __entry_ptr;    
    size_t __allocation;    
    size_t __size;    
    __libc_lock_define (, __lock)    
};   
typedef struct __dirstream DIR;  

通过opendir函数返回的dir结构可被以下函数使用:

struct dirent *readdir(DIR *dp);    
void rewinddir(DIR *dp);   
int closedir(DIR *dp);    
long telldir(DIR *dp);   
void seekdir(DIR *dp,long loc);  

二、readdir

原型

struct dirent* readdir(DIR* dir_handle);

参数与功能

DIR* dir_handle就是opendir返回的DIR结构,readdir的功能就是读一个目录。

返回值

返回是dirent结构体指针,dirent结构体成员如下

struct dirent   
{   
  long d_ino; /* inode number 索引节点号 */     
    off_t d_off; /* offset to this dirent 在目录文件中的偏移 */  
    unsigned short d_reclen; /* length of this d_name 文件名长 */  
    unsigned char d_type; /* the type of d_name 文件类型 */  
    char d_name [NAME_MAX+1]; /* file name (null-terminated) 文件名,最长255字符 */  
}  

从上述定义也能够看出来,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似ls -l那种效果的文件信息,必须要靠stat函数了。

三、stat

原型

int stat(const char *file_name, struct stat *buf);

参数与功能

file_name为readdir返回的dirent结构体中的d_name,buf为stat结构buf。

通过readdir函数读取到的文件名存储在结构体dirent的d_name成员中,而函数stat();的作用就是获取文件名为d_name的文件的详细信息,存储在stat结构体中。以下为stat结构体的定义:

struct stat {   
        mode_t     st_mode;       //文件访问权限   
        ino_t      st_ino;       //索引节点号   
        dev_t      st_dev;        //文件使用的设备号   
        dev_t      st_rdev;       //设备文件的设备号   
        nlink_t    st_nlink;      //文件的硬连接数   
        uid_t      st_uid;        //所有者用户识别号   
        gid_t      st_gid;        //组识别号   
        off_t      st_size;       //以字节为单位的文件容量   
        time_t     st_atime;      //最后一次访问该文件的时间   
        time_t     st_mtime;      //最后一次修改该文件的时间   
        time_t     st_ctime;      //最后一次改变该文件状态的时间   
        blksize_t st_blksize;    //包含该文件的磁盘块的大小   
        blkcnt_t   st_blocks;     //该文件所占的磁盘块   
};  

四、示例

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <time.h>

/* 文件大小和修改时间 */
static int get_file_size_time(const char *filename)
{
	struct stat statbuf;
	/* 判断未打开文件 */ 
	if(stat(filename,&statbuf)==-1)
	{
		printf("Get stat on %s Error: %s\n", filename, strerror(errno));
		return(-1);
	}
	if(S_ISDIR(statbuf.st_mode)) // 目录
		return(1);
	if(S_ISREG(statbuf.st_mode)) // 文件
		printf("%s size: %ld bytes\tmodified at %s", filename, statbuf.st_size, ctime(&statbuf.st_mtime));
	return(0);
}

int main(int argc,char **argv)
{
	DIR *dirp;
	struct dirent *direntp;
	int stats;

	if(argc!=2)
	{
		printf("Usage: %s filename\n\a", argv[0]);
		exit(1);
	}

	if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1)) // 文件或出现错误
		exit(1);

	/* 打开目录 */	
	if((dirp=opendir(argv[1]))==NULL)
	{
		printf("Open Directory %s Error: %s\n", argv[1], strerror(errno));
		exit(1);
	}

	/* 返回目录中文件大小和修改时间 */
	while((direntp=readdir(dirp))!=NULL) 
	{
		/* 给文件或目录名添加路径:argv[1]+"/"+direntp->d_name */
		char dirbuf[512]; 
		memset(dirbuf,0,sizeof(dirbuf)); 
		strcpy(dirbuf,argv[1]); 
		strcat(dirbuf,"/"); 
		strcat(dirbuf,direntp->d_name); 
		if(get_file_size_time(dirbuf)==-1) break;
	}

	closedir(dirp);
	exit(1);
}

运行结果:

五、总结

遍历一个文件夹中内容的布奏:

首先,使用opendir函数打开目录a,返回指向目录a的DIR结构体c。

接着,我们调用readdir( c)函数读取目录a下所有文件(包括目录),返回指向目录a下所有文件的dirent结构体d。

然后,遍历d,调用stat(d->name,stat *e)来获取每个文件的详细信息,存储在stat结构体e中。

 

参考:

https://blog.youkuaiyun.com/u012349696/article/details/50083787

https://blog.youkuaiyun.com/hb707934728/article/details/52100853

<think>好的,我现在需要帮助用户了解如何使用C语言遍历文件,并且提供示例代码。用户之前的问题是关于LVGL模拟器的配置,现在转向文件遍历,可能是在开发过程中需要处理文件系统相关功能。用户提供的引用中有几个关于C语言遍历文件夹和文件读写的例子,我需要结合这些内容来组织回答。首先,我需要确认用户的需求。用户明确询问的是“C语言遍历文件”的示例代码。根据引用中的内容,引用[1]和[3]、[4]提到了使用dirent结构体和opendir/readdir函数来遍历目录,而引用[2]和[3]涉及文件读写。因此,我应该重点讲解如何用dirent.h中的函数实现目录遍历,并给出相应的代码示例。 接下来,我需要确保回答的结构清晰。按照用户之前的示例,应该分步骤说明,包括环境准备、示例代码、代码解析、扩展功能和相关问题。同时,需要引用用户提供的引用内容,比如引用[1]中的struct dirent结构体成员,以及遍历目录的递归方法。 需要注意用户可能混淆了“遍历文件”和“遍历目录”。用户可能实际上是想遍历目录下的所有文件,而不仅仅是单个文件。因此,在回答中需要明确这一点,并解释如何递归遍历目录。另外,用户提供的引用[1]中的代码存在一些问题,比如直接使用d_reclen==24来判断是否为子目录可能不准确,因为dirent结构体的具体实现可能因系统而异。正确的做法应该是使用d_type来判断文件类型,比如DT_DIR表示目录,DT_REG表示普通文件。因此,在示例代码中需要修正这一点,以提高可移植性。 此外,代码中需要处理.和..这两个特殊目录,避免进入无限递归。用户提供的引用[1]中的代码没有处理这一点,可能导致问题,所以需要在示例代码中加入过滤条件。关于文件读写部分,用户可能需要在遍历文件后对每个文件进行操作,比如读取内容或移动文件,如引用[4]提到的移动文件函数。这部分可以作为扩展功能提到,并给出简单的示例,比如统计文件大小。最后,生成的相关问题需要与文件遍历和操作相关,比如递归遍历的优化、处理符号链接、文件过滤等,这些可以帮助用户进一步学习。 总结回答的结构: 1.基本方法:介绍dirent.h和递归遍历2.示例代码:修正用户引用中的问题,正确处理目录类型和特殊条目3.代码解析:解释关键函数和结构体4.扩展功能:文件读写、统计等5.注意事项:特殊目录处理、错误处理等6.相关问题:自然延伸的问题需要确保代码示例正确且可运行,并符合现代C语言标准,同时兼容不同系统(如Linux和Windows,但注意dirent.h在Windows可能需要额外库)。由于用户之前的开发环境是Windows下的VSCode,可能需要提到在Windows下使用dirent.h的注意事项,比如通过MinGW或Cygwin。最后,检查LaTeX格式是否正确,数学表达式是否用$...$或$$...$$包裹,引用标记是否正确添加,确保回答符合用户提供的系统级指令。</think>### C语言遍历文件实现方法及示例 #### 一、基本实现原理 在C语言遍历文件系统需要依赖`dirent.h`头文件提供的目录操作函数,主要通过以下步骤实现: 1. 使用`opendir()`打开目录流 2. 通过`readdir()`循环读取目录项 3. 根据`struct dirent`结构体成员判断文件类型 4. 递归处理子目录[^1] #### 二、完整示例代码 ```c #include <stdio.h> #include <dirent.h> #include <sys/stat.h> #include <string.h> void traverse_directory(const char *path) { DIR *dir = opendir(path); if (!dir) return; struct dirent *entry; while ((entry = readdir(dir)) != NULL) { // 跳过特殊目录 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; // 构造完整路径 char full_path[1024]; snprintf(full_path, sizeof(full_path), "%s/%s", path, entry->d_name); // 判断文件类型 if (entry->d_type == DT_DIR) { printf("[目录] %s\n", full_path); traverse_directory(full_path); // 递归处理子目录 } else if (entry->d_type == DT_REG) { printf("[文件] %s\n", full_path); // 此处可添加文件操作代码 } } closedir(dir); } int main(int argc, char *argv[]) { if (argc != 2) { printf("用法: %s <目录路径>\n", argv[0]); return 1; } traverse_directory(argv[1]); return 0; } ``` #### 三、关键代码解析 1. **目录流操作** - `DIR *dir = opendir(path)`:打开目录流 - `readdir(dir)`:读取目录项信息 - `closedir(dir)`:关闭目录流[^3] 2. **文件类型判断** ```c entry->d_type == DT_DIR // 判断是否为目录 entry->d_type == DT_REG // 判断是否为普通文件 ``` 相比直接检查`d_reclen`,使用`d_type`判断更可靠[^1] 3. **路径拼接** 使用`snprintf`拼接完整路径,避免直接操作字符串缓冲区溢出 #### 四、扩展功能示例 结合文件读写操作统计文件大小: ```c void get_file_size(const char *filename) { FILE *file = fopen(filename, "rb"); if (!file) return; fseek(file, 0, SEEK_END); long size = ftell(file); rewind(file); printf("文件 %s 大小: %ld 字节\n", filename, size); fclose(file); } ``` 在遍历到文件时调用该函数即可[^2] #### 五、注意事项 1. **特殊目录处理** 必须过滤`.`(当前目录)和`..`(上级目录),否则会导致无限递归 2. **错误处理** 建议添加`errno`检查: ```c if (dir == NULL) { perror("打开目录失败"); return; } ``` 3. **跨平台兼容性** - Linux/macOS原生支持`dirent.h` - Windows需使用MinGW或通过`FindFirstFile`API实现 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值