文件系统常见函数
write系统调用
#include <unistd.h>
ssize_t write(int fd, const void *buf, size_t count);
参数说明
-
fd 文件描述符,指向已打开的文件或设备(如标准输出 1、文件句柄等
-
buf 指向待写入数据的缓冲区指针,支持任意数据类型(如字符数组,结构体等)
-
count 指定需要写入的字节数(从buf中读取的最大的长度)
返回值
-
成功时 返回实际写入的字节数(可能小于
count
,如磁盘空间不足或管道缓冲区满)。 -
失败时 返回
-1
,并通过全局变量errno
标识具体错误类型(如权限不足、文件未打开等)
#include <unistd.h> // 包含系统调用相关函数(如 write)
#include <stdlib.h> // 包含 exit 函数int main()
{// 向文件描述符 1(标准输出)写入 18 字节数据if ((write(1, "Here is some data\n", 18)) != 18)// 若实际写入字节不等于 18,向文件描述符 2(标准错误)输出错误信息write(2, "A write error has occurred on file descriptor 1\n", 46);exit(0); // 无论是否出错,都以状态码 0 退出
}
read系统调用
#include <unistd.h> // 提供 read/write 系统调用
#include <stdlib.h> // 提供 exit 函数int main() {char buffer[128]; // 定义 128 字节的输入缓冲区int nread; // 存储 read 的返回值// 从标准输入(fd=0)读取最多 128 字节到 buffernread = read(0, buffer, 128);// 处理读取错误if (nread == -1)write(2, "A read error has occurred\n", 26); // 向标准错误(fd=2)输出// 将读取的数据写入标准输出(fd=1)if ((write(1, buffer, nread)) != nread)write(2, "A write error has occurred\n", 27); // 处理写入错误exit(0); // 程序退出
}
核心逻辑流程 1.数据读取
-
通过 read(0, buffer, 128) 从标准输入(如键盘、管道或重定向文件)读取数据
-
返回实际读取的字节数 nread(可能小于 128)
-
返回 -1 表示读取失败(如无权限、中断等)
2.错误处理
-
读取错误:若 nread == -1,向标准错误输出提示
-
写入错误:若实际写入字节数不等于 nread(如磁盘满、管道破裂等),输出错误信息
3.数据转发
-
将缓冲区内容通过 write(1, buffer, nread) 原样写入标准输出(如终端屏幕或重定向文件)
open
系统调用详解
1. 基本概念与作用
-
功能定义
open
是Linux文件操作的核心系统调用,用于打开或创建文件,返回唯一的文件描述符(非负整数),供后续read
/write
等操作使用12。 -
与库函数对比 区别于标准I/O库的
fopen
,open
是底层无缓冲操作,直接操作文件描述符而非文件流
#include <fcntl.h>
#include <sys/stat.h>int open(const char *pathname, int flags); // 基础形式
int open(const char *pathname, int flags, mode_t mode); // 创建文件时需指定权限- pathname文件路径(绝对或相对)"/home/user/file.txt"flags控制打开方式和行为的标志位(必选参数)O_RDWR | O_CREAT | O_APPENDmode新文件权限(仅当flags含O_CREAT时有效)0644(rw-r--r--)O_RDONLY:只读
O_WRONLY:只写
O_RDWR:读写//O_CREAT 文件不存在时创建新文件(需配合mode参数)
//O_EXCL 与O_CREAT联用,若文件存在则返回错误(用于原子性创建)
//O_TRUNC 打开时清空文件内容(仅对普通文件有效)
//O_APPEND 写操作前自动定位到文件末尾(避免并发写入覆盖)
//O_NONBLOCK 非阻塞模式打开(适用于管道、设备文件等)
close
系统调用详解
#include <unistd.h>
int close(int fd);
一个文件复制程序
#include <unistd.h> // 提供 read/write/open 系统调用
#include <sys/stat.h> // 提供文件权限宏(如 S_IRUSR)
#include <fcntl.h> // 提供文件打开标志(如 O_RDONLY)
#include <stdlib.h> // 提供 exit 函数int main(){char c; // 单字节缓冲区int in, out; // 输入/输出文件描述符// 打开输入文件(只读模式)in = open("file.in", O_RDONLY);// 打开输出文件(写入模式,不存在则创建,权限:用户可读可写)out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);// 逐字节读取输入文件while (read(in, &c, 1) == 1) {// 将字节写入输出文件write(out, &c, 1);}exit(0); // 程序退出(未显式关闭文件描述符)
}
核心逻辑与流程
-
打开文件
-
file.in
:以只读模式打开(若不存在则失败) -
file.out
:以写入模式打开,不存在时创建,权限为0600
(用户可读写)
-
-
数据复制
-
每次读取 1 字节到变量
c
-
将
c
写入目标文件(每次 1 字节)
-
-
终止程序
-
通过
exit(0)
退出,未显式关闭文件描述符(由内核自动处理)
-
#include <unistd.h> // 系统调用:read/write/open/close
#include <sys/stat.h> // 文件权限宏(S_IRUSR等)
#include <fcntl.h> // 文件打开标志(O_RDONLY等)
#include <stdlib.h> // exit函数int main() {char block[1024]; // 缓冲区(1KB)int in, out; // 输入/输出文件描述符int nread; // 实际读取的字节数// 打开输入文件(只读模式)in = open("file.in", O_RDONLY);// 打开输出文件(写入模式,不存在则创建,权限:用户可读可写)out = open("file.out", O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR);// 循环读取输入文件到缓冲区while ((nread = read(in, block, sizeof(block))) > 0) {// 将缓冲区内容写入输出文件write(out, block, nread);}exit(0); // 退出程序(未显式关闭文件描述符)
}
fopen函数
FILE *fopen(const char *filename, const char *mode);
//filename 文件路径字
//mode 文件打开模式
#include <stdio.h>int main() {FILE *fp = fopen("data.txt", "r"); // 以只读模式打开文件if (fp == NULL) {perror("文件打开失败"); // 输出错误信息(如 "No such file or directory")return 1;}// 文件操作...fclose(fp); // 关闭文件流return 0;
}
fread函数
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
参数解析
-
ptr:指向存储读取数据的内存缓冲区的指针(需预先分配足够空间)
-
size:每个数据项的字节大小(例如 sizeof(int) 或 sizeof(struct))
-
nmemb:要读取的数据项数量
-
stream:指向已打开的文件的 FILE 指针(需通过 fopen 打开)
返回值
-
成功时返回 实际读取的数据项数量(若小于 nmemb,可能因文件结束或错误)
-
返回0 表示读取失败或到达文件末尾
#1.打开文件流
FILE *fp = fopen("data.bin", "rb"); // 以二进制只读模式打开文
if (fp == NULL) {perror("文件打开失败");exit(EXIT_FAILURE);
}#2.分配缓冲区
int buffer[100];#3.调用fread函数
size_t num_read = fread(buffer, sizeof(int), 100, fp);
if (num_read < 100) {if (feof(fp)) // 检查是否到达文件末printf("已读取到文件末尾,实际读取数量:%zu\n", num_read);else if (ferror(fp)) // 检查是否发生错perror("读取错误");
}
fwrite函数
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
参数说明:
-
ptr:指向待写入数据的缓冲区首地址(如数组、结构体或动态分配的内存块)
-
size:单个数据项的字节大小(通常用 sizeof() 运算符获取,如 sizeof(int))
-
nmemb:要写入的数据项数量(例如数组元素个数)
-
stream:目标文件指针,需通过 fopen 以二进制模式(如 "wb"、"ab")打开
返回值:
-
成功时返回实际写入的数据项数量(非字节数)
-
若返回值小于 nmemb,需用 ferror() 检查错误或 feof() 判断是否到达文件末尾
示例1:写入字符串
#include <stdio.h>int main() {FILE *fp;if (fopen_s(&fp, "text.txt", "wb") != 0) { // 以二进制模式写perror("文件打开失败");return -1;}char buffer[] = "Hello, fwrite!";size_t written = fwrite(buffer, sizeof(char),sizeof(buffer), fp);fclose(fp);return 0;
}
#示例2:写入结构体数组
typedef struct {int id;float score;
} Student;int main() {Student students[] = {{1, 90.5}, {2, 85.0}};FILE *fp = fopen("students.dat", "wb");if (!fp) {perror("文件打开失败");return 1;}size_t num_written = fwrite(students, sizeof(Student), 2, fp);fclose(fp);return 0;
}
fclose函数
int fclose(FILE *stream);
-
参数:
stream
为fopen
或freopen
返回的文件指针,指向需要关闭的文件流。 -
返回值
-
成功:返回
0
。 -
失败:返回
EOF
(通常为-1
),需检查errno
获取具体错误原因(如EINVAL
表示参数无效)。
-
2. 核心功能
-
关闭文件流:释放文件占用的系统资源,解除文件指针与底层文件的关联23。
-
刷新缓冲区:将缓冲区中未写入的数据同步到磁盘,确保数据完整性
3. 使用步骤
-
检查文件指针有效性
FILE *fp = fopen("data.txt", "r");
if (fp == NULL) { perror("文件打开失败"); exit(EXIT_FAILURE);
}
2.操作文件(如读写)后调用 fclose
// 文件读写操作...
int ret = fclose(fp);
if (ret != 0) { perror("关闭文件失败");
}
fflush函数
int fflush(FILE *stream);
-
参数
-
stream
:指向FILE
类型指针,标识需刷新的文件流(如stdout
、stderr
或已打开的文件指针)。 -
若
stream
为NULL
,则刷新所有已打开的输出流的缓冲区。
-
-
返回值
-
成功:返回
0
。 -
失败:返回
EOF
,并通过ferror()
检查错误原因(如磁盘空间不足或流未打开)。
-
2. 核心功能
-
刷新输出流缓冲区:强制将缓冲区中未写入的数据立即同步到文件或设备(如磁盘、终端)。
-
适用场景:
-
确保关键数据在程序崩溃前持久化(如日志文件)。
-
交互式程序需即时显示输出(如进度条或调试信息)。
-
多线程环境下避免缓冲区竞争。
-
3. 使用示例
示例 1:强制刷新 stdout
#include <stdio.h>
int main() { printf("正在加载..."); fflush(stdout); // 立即输出,无需等待换行符 // 耗时操作... printf("完成\n"); return 0;
}
示例 2:刷新文件流
FILE *fp = fopen("data.txt", "w");
if (fp) { fprintf(fp, "重要数据"); fflush(fp); // 确保数据写入磁盘 // 其他操作... fclose(fp);
}
fseek函数
fseek 是 C 语言标准库中用于控制文件指针位置的核心函数,支持文件的随机访问操作。以下是其核心要点:
int fseek(FILE *stream, long offset, int origin);
-
stream:指向已打开文件的指针,需确保文件支持定位操作(如 r+、w+ 模式)
-
offset:相对于 origin 的偏移量(单位:字节),可为正(向后偏移)或负(向前偏移)
-
origin:基准位置,可选常量:
-
SEEK_SET(文件开头)
-
SEEK_CUR(当前位置)
-
SEEK_END(文件末尾)
-
2. 返回值与功能
-
功能:重新定位文件指针到 origin + offset 的位置,突破顺序读写的限制
-
返回值:成功返回 0,失败返回非零值(通常为 -1)
3. 核心应用场景
-
随机读写:直接跳转到文件任意位置读写数据(如修改文件中间部分内容)
-
二进制文件操作:精准定位数据块(如读取结构体数组中的特定元素)
-
结合其他函数:
-
与 ftell 配合获取当前指针位置
-
与 rewind 等效于 fseek(stream, 0, SEEK_SET)
-
4. 示例代码
#include <stdio.h>
int main() { FILE *fp = fopen("data.txt", "r+"); if (fp == NULL) { perror("Error opening file"); return 1; } // 跳转到第 4 个字节(从文件开头) fseek(fp, 3, SEEK_SET); char ch = fgetc(fp); // 读取第四个字符 printf("Character at position 3: %c\n", ch); fclose(fp); return 0;
}
fgetc,getc和getchar函数
1. 函数原型与定义
fgetc
int fgetc(FILE *stream);
从指定文件流(如文件指针或 stdin)读取单个字符,返回 int 类型的字符值(无符号字符转换为 int)或 EOF(错误或文件末尾)
getc
int getc(FILE *stream)
-
功能与 fgetc 完全相同,但通常以宏实现,执行效率更高(编译时直接展开代码)
-
注意:若参数 stream 是表达式(如 getc(fp++)),可能导致未定义行为(宏参数被多次求值)
getchar
int getchar(void)
等同于 getc(stdin),专用于从标准输入(键盘)读取字符
2. 核心区别
-
. 共同点与返回值
-
返回值:
-
成功时返回读取的字符(转换为 int),失败或文件末尾返回 EOF
-
需通过 feof() 或 ferror() 区分错误类型(如磁盘错误 vs 文件结束)
-
-
缓冲区行为:
均从输入缓冲区读取数据,若缓冲区为空则等待用户输入(如键盘输入需按回车键触发读取)
#1.fgetc读取文件
FILE *fp = fopen("data.txt", "r");
if (fp) { int c; //fgetc读取单个字符 while ((c = fgetc(fp)) != EOF) { putchar(c); } fclose(fp);
} #2.getc高效读取
FILE *fp = fopen("log.txt", "r");
if (fp) { int c = getc(fp); // 宏展开,无函数调用开销 // 处理字符... fclose(fp);
} #getchar读取键盘输入
printf("输入一个字符:");
int c = getchar(); // 等同于 getc(stdin)
if (c != EOF) { printf("你输入的是:%c\n", c);
}
文件和目录访问权限
chmod函数调用详解
chmod
是 Linux/Unix 系统中用于修改文件权限的系统调用函数,通过指定路径或文件描述符调整文件的访问权限。以下是其核心要点及用法:
1.函数原型与参数
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode); // 基于路径修改权限
int fchmod(int fd, mode_t mode); // 基于文件描述符修改权限
-
pathname:目标文件路径(相对或绝对路径)。
-
fd:已打开文件的描述符(需确保文件已通过 open 等函数打开)。
-
mode:权限模式值,通常为八进制数(如 0644)或宏组合(如 S_IRUSR | S_IWGRP)
#include <stdio.h>
#include <sys/stat.h>
#include <stdlib.h> int main() { const char *filename = "test.txt"; int res = chmod(filename, 0644); // 修改为用户可读写,组和其他用户只读 if (res == -1) { perror("chmod failed"); // 输出错误信息(如权限不足) exit(1); } printf("权限修改成功\n"); return 0;
}
chown
函数调用详解
chown
是 Linux/Unix 系统中用于修改文件所有者(用户 ID)和所属组(组 ID)的系统调用函数,支持通过路径或文件描述符操作。以下是其核心要点及用法:
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group); // 基于路径修改属主
int fchown(int fd, uid_t owner, uid_t group); // 基于文件描述符修改属主
int lchown(const char *pathname, uid_t owner, gid_t group); // 修改符号链接本身的属主
#include <unistd.h>
#include <stdio.h> int main() { const char *filename = "test.txt"; uid_t new_owner = 1000; // 用户 ID(通过 /etc/passwd 查询) gid_t new_group = 1000; // 组 ID(通过 /etc/group 查询) if (chown(filename, new_owner, new_group) == -1) { perror("chown failed"); return 1; } printf("文件属主修改成功\n"); return 0;
}
opendir函数
opendir 是 Linux/Unix 系统中用于打开目录的标准库函数,属于目录操作的核心 API,需结合 readdir 和 closedir 实现目录遍历。以下是其关键知识点及用法:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
-
参数 name:需打开的目录路径(绝对或相对路径),需以 \0 结尾的字符串形式传入
-
返回值:
-
成功:返回 DIR* 类型的目录流指针,用于后续操作(如读取目录项)
-
失败:返回 NULL,并设置 errno 标识具体错误
-
使用流程与示例
步骤:
1.调用 opendir 打开目录并获取 DIR* 流指针。
2.使用 readdir 逐项读取目录内容。
3.操作完成后调用 closedir 关闭目录流
#include <dirent.h>
#include <stdio.h> int main() { DIR *dir = opendir("."); // 打开当前目录if (dir == NULL) { perror("opendir failed"); return 1; } struct dirent *entry; while ((entry = readdir(dir)) != NULL) { // 遍历目录项 printf("文件名: %s\n", entry->d_name); } closedir(dir); // 关闭目录流 return 0;
}
注意事项
-
资源管理:必须显式调用 closedir 释放目录流,避免资源泄漏
-
符号链接:opendir 默认跟随符号链接打开目标目录,若需操作链接自身需结合其他函数(如 lstat)
-
并发安全:目录内容在遍历过程中可能被其他进程修改,需注意竞态条件
代码解析
1.struct dirent结构体定义
-
struct dirent 是系统预定义的目录项结构体,用于存储单个目录项(文件或子目录)的信息
-
其典型成员包括:
struct dirent { ino_t d_ino; // 文件的 inode 编号 char d_name[256]; // 文件名(以 \0 结尾的字符串) // 其他成员可能因系统不同而异(如 d_type、d_reclen 等)
};
2.指针声明
-
entry 是一个指向 struct dirent 的指针变量,用于接收 readdir() 函数返回的目录项数据
-
通过该指针可访问当前遍历项的文件名、inode 等信息,例如:
printf("文件名: %s\n", entry->d_name); // 输出当前文件
printf("inode: %lu\n", entry->d_ino); // 输出当前文件的 inod
3.典型使用场景
结合 opendir
、readdir
、closedir
实现目录遍历:
#include <dirent.h>
DIR *dir = opendir("."); // 打开当前目录
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) { // 逐项读取目录内容// 处理 entry 指向的目录项
}
closedir(dir); // 关闭目录
-
readdir 的作用:每次调用返回下一个目录项的指针,遍历完成或出错时返回 NULL
注意事项
-
内存管理:entry 指针指向的内存由 readdir 函数内部管理,无需手动释放
-
线程安全:readdir 非线程安全,多线程环境需用 readdir_r
-
隐藏文件:遍历结果包含 .(当前目录)和 ..(上级目录),需根据业务过滤
readdir 函数详解
readdir 是 Linux/Unix 系统中用于遍历目录内容的核心函数,需与 opendir 和 closedir 配合使用。以下是其核心知识点及用法:
1. 函数原型与头文件
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
-
参数 dirp:由 opendir 返回的目录流指针,指向待遍历的目录
-
返回值:
-
成功:返回指向 struct dirent 的指针,包含当前目录项信息
-
失败/遍历结束:返回 NULL(若出错,需检查 errno)
-
2. struct dirent 结构体成员
struct dirent 用于存储目录项信息,关键成员包括:
struct dirent { ino_t d_ino; // 文件的 inode 编 char d_name[256]; // 文件名(以 `\0` 结尾的字符串unsigned char d_type; // 文件类型(如 DT_REG 普通文件,DT_DIR 目录// 其他字段如 d_reclen(记录长度)、d_off(偏移量)可能因系统不同而存
};
#注:d_name 是标准必用字段,d_type 非所有系统都支持
3.典型使用流程
#include <dirent.h>
DIR *dir = opendir("."); // 打开当前目录
struct dirent *entry;
while ((entry = readdir(dir)) != NULL) { printf("文件名: %s\n", entry->d_name); // 输出文件名 if (entry->d_type == DT_REG) { printf("普通文件\n"); }
}
closedir(dir); // 关闭目录流
entry->d_name 代码解析
entry->d_name 是 C 语言中用于访问目录项名称的语法,其核心含义和用途如下:
1. 定义与数据结构
-
entry 是 struct dirent 类型的指针,指向由 readdir() 函数读取的目录项信息
-
d_name 是 struct dirent 结构体的成员变量,用于存储文件名(或子目录名),类型为 char[256] 的字符数组,以 \0 结尾
2. 典型用途
-
获取文件名:通过 entry->d_name 可获取当前遍历到的文件或子目录的名称,例如:
-
while ((entry = readdir(dir)) != NULL) { printf("文件名: %s\n", entry->d_name); // 输出当前文件/子目录名称 }
过滤特殊目录项:在遍历目录时,通常需跳过
.
(当前目录)和..
(上级目录):
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { continue; // 跳过特殊目录项
}
-
与其他函数配合:结合
stat()
或lstat()
函数获取文件详细信息:
struct stat file_info;
lstat(entry->d_name, &file_info); // 根据文件名获取元数据
3. 注意事项
数据类型限制:d_name 仅存储名称,不包含路径信息。需手动拼接路径(如 snprintf(path, sizeof(path), "%s/%s", dir_path, entry->d_name);) 跨平台兼容性:d_name 是标准字段,在所有支持 POSIX 的系统(如 Linux、Unix)中可用
stat()
与 lstat()
函数详解
stat()
和 lstat()
是 Linux/Unix 系统中用于获取文件元数据的核心函数,需包含头文件 <sys/stat.h>
和 <sys/types.h>
。以下为关键知识点及用法总结:
1.函数原型与区别
int stat(const char *pathname, struct stat *buf); // 通过路径获取文件信息
int lstat(const char *pathname, struct stat *buf); // 针对符号链接返回链接本身信息(而非目标文件)
参数 pathname:文件或目录的路径。
• 参数 buf:存储文件属性的 struct stat 结构体指针
• 返回值:成功返回 0,失败返回 -1 并设置 errno
核心区别:
• stat() 对符号链接会解析到目标文件,而 lstat() 仅获取链接自身的属性
2.struct stat 结构体成员
&file_stat
&file_stat 是 C 语言中用于获取 struct stat 类型变量地址的语法,其核心作用如下:
1. 语法解析与用途
• 取地址运算符:& 运算符用于获取变量 file_stat 的内存地址
• 配合系统函数:stat()、lstat() 等函数需通过指针参数写入文件属性数据,因此需将 file_stat 的地址传递给函数
示例:
struct stat file_stat;
stat("test.txt", &file_stat); // &file_stat 作为指针参数传入函数
2. 关键知识点
• 函数参数要求:stat() 函数的第二个参数类型为 struct stat *(指向结构体的指针),必须传递地址而非变量本身
• 数据写入机制:函数内部通过指针直接修改 file_stat 的内存,无需返回值即可保存文件属性信息
telldir 函数详解
1. 功能与定义
telldir() 用于获取目录流的当前位置偏移量,返回值表示距离目录文件开头的偏移值,常用于与 seekdir() 配合实现目录遍历的断点续扫
• 函数原型:
#include <dirent.h>
long int telldir(DIR *dirp); // Linux 标准定义•
off_t telldir(DIR *dirp); // 部分系统使用 off_t 类型•
- 参数:dirp 为 opendir() 打开的目录流指针。
- 返回值:
- 成功:返回当前偏移量(长整型或 off_t 类型)。
- 失败:返回 -1,并设置 errno 为 EBADF(目录流无效)
2. 核心应用场景
1. 目录遍历状态保存
在遍历目录时记录偏移量,便于后续通过 seekdir() 恢复至指定位置,避免重复扫描
DIR *dir = opendir("/path");
struct dirent *entry;
long pos;
while ((entry = readdir(dir)) != NULL) { pos = telldir(dir); // 记录当前偏移量// 处理 entry
}
seekdir(dir, pos); // 恢复到最后记录的位置
entry 是一个指向 struct dirent 的指针变量,用于接收 readdir() 函数返回的目录项数据
seekdir 函数详解
1. 功能与定义
seekdir() 用于设置目录流的读取位置,允许通过指定偏移量跳转至目录项的特定位置,常与 telldir() 配合实现断点续扫或随机访问目录内容
函数原型:
#include <dirent.h>
void seekdir(DIR *dirp, off_t offset);
-
参数:
-
dirp:由 opendir() 打开的目录流指针。
-
offset:目标偏移量,必须为 telldir() 的返回值,否则行为未定义
2. 核心应用场景
1.恢复目录遍历位置 通过 telldir() 记录偏移量,后续使用 seekdir() 恢复至该位置,适用于中断后继续读取目录的场景
DIR *dir = opendir("/path");
off_t pos = telldir(dir); // 记录当前偏移量:ml-citation{ref="5,7" data="citationList"}
// ...(其他操作)
seekdir(dir, pos); // 恢复至记录位置:ml-citation{ref="1,8" data="citationList"}
closedir 函数详解
1. 功能与定义
closedir() 用于关闭由 opendir() 打开的目录流,释放相关系统资源,防止内存泄漏和文件描述符耗尽:
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
#include <unistd.h> // 提供系统调用(如 chdir)
#include <stdio.h> // 标准输入输出(如 printf)
#include <dirent.h> // 目录操作(opendir, readdir)
#include <string.h> // 字符串处理(如 strcmp)
#include <sys/stat.h> // 文件状态(stat, lstat)
#include <stdlib.h> // 标准库函数(如 exit)/*dir:当前要遍历的目录路径* depth:缩进深度,用于展示层级结构*/
void printdir(char *dir, int depth)
{DIR *dp;struct dirent *entry;struct stat statbuf;1.打开目录/*尝试打开目录,失败则报错返回。*/if((dp = opendir(dir)) == NULL) {fprintf(stderr,"cannot open directory: %s\n", dir);return;}2.进入目录chdir(dir);//切换到目标目录,以便处理其内部条目。3.遍历目录whiile((entry = readdir(dp)) != NULL) {//readdir:逐个读取目录中的条目(文件或子目录)。//lstat:获取条目的元数据(如文件类型)lstat(entry->d_name,&statbuf);4.处理子目录S_ISDIR 系统定义的宏 通过解析st_mode的二进制判断文件是否为目录statbuf.st_mode 属于struct stat结构体if(S_ISDIR(statbuf.st_mode)) {/* Found a directory, but ignore . and .. */if(strcmp(".",entry->d_name) == 0 ||strcmp("..",entry->d_name) == 0)continue;printf("%*s%s/\n",depth,"",entry->d_name);/* Recurse at a new indent level */printdir(entry->d_name,depth+4); //递归处理子目录}else printf("%*s%s\n",depth,"",entry->d_name);}chdir("..");closedir(dp);
}
opendir() 打开目录流,返回 DIR* 指针。
readdir() 读取目录中的下一个条目,返回 struct dirent(包含文件名 d_name)。
lstat() 获取文件元数据(如类型、权限),避免解引用符号链接。
S_ISDIR(st_mode) 宏:检查条目是否为目录。
chdir() 切换当前工作目录。