文件系统常见函数
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() 切换当前工作目录。
相关文章:
文件系统常见函数
write系统调用 #include <unistd.h> ssize_t write(int fd, const void *buf, size_t count); 参数说明 fd 文件描述符,指向已打开的文件或设备(如标准输出 1、文件句柄等 buf 指向待写入数据的缓冲区指针,支持任意数据类型…...
深入理解 G1 GC:已记忆集合(RSet)与收集集合(CSet)详解
已记忆集合(RSet)与收集集合(CSet)详解 深入理解 G1 GC:已记忆集合(RSet)与收集集合(CSet)详解一、 引言:G1 GC 的基石二、 已记忆集合 (RSet):跟…...
Android Cordova 开发 - Cordova 解读初始化项目(index.html meta、Cordova.js、config.xml)
一、index.html meta 1、Content-Security-Policy (1)基本介绍 <meta http-equiv"Content-Security-Policy" content"default-src self data: https://ssl.gstatic.com unsafe-eval; style-src self unsafe-inline; media-src *; i…...
uv run 都做了什么?
uv run 都做了什么? uv run <命令> [参数...] 的主要作用是:在一个由 uv 管理或发现的 Python 虚拟环境中,执行你指定的 <命令>。它会临时配置一个子进程的环境,使其表现得如同该虚拟环境已经被激活一样。这意味着&am…...
Maven 依赖坐标与BOM统一管理
🧑 博主简介:CSDN博客专家,历代文学网(PC端可以访问:https://literature.sinhy.com/#/?__c1000,移动端可微信小程序搜索“历代文学”)总架构师,15年工作经验,精通Java编…...
UV: Python包和项目管理器(从入门到不放弃教程)
目录 UV: Python包和项目管理器(从入门到不放弃教程)1. 为什么用uv,而不是conda或者pip2. 安装uv(Windows)2.1 powershell下载2.2 winget下载2.3 直接下载安装包 3. uv教程3.1 创建虚拟环境 (uv venv) 4. uvx5. 此pip非…...
32单片机——GPIO的工作模式
1、GPIO GPIO(General Purpose Input Output,通用输入输出端口)是控制或者采集外部器件的信息的外设,即负责输入输出。它按组分配,每组16个IO口,组数视芯片而定。STM32F103ZET6芯片是144脚的芯片࿰…...
Science Robotics 新型层级化架构实现250个机器人智能组队,“单点故障”系统仍可稳定运行
近期,比利时布鲁塞尔自由大学博士生朱炜煦与所在团队提出了一种创新的机器人群体架构——“自组织神经系统”(SoNS,Self-organizing Nervous System)。 它通过模仿自然界中的生物神经系统的组织原理,为机器人群体建立了…...
【HFP】蓝牙HFP协议来电处理机制解析
目录 一、协议概述与技术背景 1.1 HFP协议演进 1.2 核心角色定义 1.3 关键技术指标 二、来电接入的核心交互流程 2.1 基础流程概述:AG 的 RING 通知机制 2.2 HF 的响应:本地提醒与信令交互 三、带内铃声(In-Band Ring Tone࿰…...
03-谷粒商城笔记
一个插件的install和生命周期的报错是不一样的 Maven找不到ojdbc6和sqljdbc4依赖包 这时候我找到了jar包,然后我就先找到一个jar安装到了本地仓库。 在终端上进行命令了: mvn install:install-file -DfileD:\ojdbc6-11.2.0.4.jar -DgroupIdcom.oracle …...
PHP 反序列化CLI 框架类PHPGGC 生成器TPYiiLaravel 等利用
# 反序列化链项目 -PHPGGC&NotSoSecure -NotSoSecure https://github.com/NotSoSecure/SerializedPayloadGenerator 为了利用反序列化漏洞,需要设置不同的工具,如 YSoSerial(Java) 、 YSoSerial.NET 、 PHPGGC 和它的先决条件。 Deserializati…...
LeetCode热题100——283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12] 输出: [1,3,12,0,0] 示例 2: 输入: nums [0] 输出:…...
C++入门小馆: 探寻vector类
嘿,各位技术潮人!好久不见甚是想念。生活就像一场奇妙冒险,而编程就是那把超酷的万能钥匙。此刻,阳光洒在键盘上,灵感在指尖跳跃,让我们抛开一切束缚,给平淡日子加点料,注入满满的pa…...
力扣hot100_链表(3)_python版本
一、25. K 个一组翻转链表 1.1、206. 反转链表 py代码 class ListNode:def __init__(self, val0, next node):self.val valself.next next class Solution:def reverseList(self, head):pre Nonecur headwhile cur:next cur.nextcur.next prepre curcur nextreturn p…...
Lua 第9部分 闭包
在 Lua 语言中,函数是严格遵循词法定界的第一类值。 “第一类值”意味着 Lua 语言中的函数与其他常见类型的值(例如数值和字符串)具有同等权限: 一个程序可以将某个函数保存到变量中(全局变量和局部变量均可&a…...
【Linux】冯诺依曼体系结构及操作系统架构图的具体剖析
目录 一、冯诺依曼体系结构 1、结构图 2、结构图介绍: 3、冯诺依曼体系的数据流动介绍 4、为什么在该体系结构中要存在内存? 二、操作系统架构图介绍 1、操作系统架构图 2、解析操作系统架构图 3、为什么要有操作系统? 前些天发现了一…...
解析虚拟机与Docker容器化服务的本质差异及Docker核心价值
解析虚拟机与Docker容器化服务的本质差异及Docker核心价值 1.1 硬件虚拟化与操作系统级虚拟化 虚拟机(VM)基于硬件级虚拟化技术(Hypervisor),通过模拟完整硬件栈(CPU、内存、存储、网络)创建独…...
FreeRTOS深度解析:队列集(Queue Sets)的原理与应用
FreeRTOS深度解析:队列集(Queue Sets)的原理与应用 什么是队列集? 在FreeRTOS中,队列集(Queue Sets,英文名xQueueSet)是一种强大的数据结构,用于高效管理多个队列。它的…...
java将pdf转换成word
1、jar包准备 在项目中新增lib目录,并将如下两个文件放入lib目录下 aspose-words-15.8.0-jdk16.jar aspose-pdf-22.9.jar 2、pom.xml配置 <dependency><groupId>com.aspose</groupId><artifactId>aspose-pdf</artifactId><versi…...
网络原理 - 6
目录 4. 滑动窗口 滑动窗口出现丢包 情况一:数据报已经抵达,ACK 被丢了编辑 情况二:数据报直接就丢了 5. 流量控制 完! 4. 滑动窗口 这个滑动窗口是 TCP 中非常有特点的机制。 我们知道,TCP 是通过确认应答&…...
【Linux网络】构建类似XShell功能的TCP服务器
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
Spring AI - Redis缓存对话
先看效果 对话过程被缓存到了Redis 中。 原理 在上一节我们快速入门了SpringAI,具体文章请查看:快速入门Spring AI 创建 ChatClient 的代码如下: this.chatClient ChatClient.builder(chatModel).defaultSystem(DEFAULT_PROMPT).defaultAd…...
rk3588 驱动开发(二)第四章嵌入式 Linux LED 驱动开发实验
4.1 Linux 下 LED 灯驱动原理 Linux 下的任何外设驱动,最终都是要配置相应的硬件寄存器。所以本章的 LED 灯驱动 最终也是对 RK3588 的 IO 口进行配置,与裸机实验不同的是,在 Linux 下编写驱动要符合 Linux 的驱动框架。开发板上的 LED 连接…...
第49讲:AI驱动的农业碳汇估算与生态价值评估 —— 打造更“绿”的智慧农业未来
目录 🌍 一、农业碳汇:我们为什么要关心它? 🤖 二、AI是如何介入农业碳汇评估的? 🛠 三、案例实战:AI估算区域农田碳汇储量 📍 场景设定: 📊 数据来源: 🔁 处理流程: 📈 四、生态价值评估:从碳储量到生态效益 🧭 五、平台与工具推荐 💬 六、…...
springmvc入门案例
目录 前言 springmvc概述 springmvc入门案例(使用配置类替代原本的web.xml) 第一步、创建一个web工程 第二步、引入相应的依赖(servlet-api、spring-webmvc、) 第三步、编写 SpringMVC配置类,并开启包扫描功能 第四步、编写…...
Node.js学习
概述 Node.js 是一个基于 Chrome V8 引擎 的 JavaScript 运行时环境,允许在服务器端运行 JavaScript 代码。它采用事件驱动和非阻塞 I/O 模型,适合构建高性能、可扩展的网络应用,尤其擅长处理实时应用和大规模数据密集型场景 背景 JavaScri…...
SQL注入漏洞中会使用到的函数
目录 一、信息获取函数 1. 通用函数 2. 元数据查询(INFORMATION_SCHEMA) 二、字符串操作函数 1. 字符串连接 2. 字符串截取 3. 编码/解码 三、报错注入专用函数 1. MySQL 2. SQL Server 3. PostgreSQL 四、时间盲注函数 1. 通用延迟 2. 计…...
MIT IDSS深度解析:跨学科融合与系统科学实践
麻省理工学院的IDSS(Institute for Data, Systems, and Society, IDSS)是一个致力于通过先进分析方法推动教育与研究的前沿机构。它将工程学、信息科学和数据科学的方法与社会科学的分析方法相结合,以应对复杂的社会挑战。 MIT IDSS 建立在统计学、计算机科学和特定应用领域…...
重塑智慧出行新生态,德赛西威全新战略愿景发布
4月22日,上海车展开幕前夕,德赛西威以“智新境,向远大”为主题,正式对外发布全新发展战略及使命、愿景;同时,代表未来AI出行趋势的智慧出行解决方案Smart Solution 3.0重磅亮相。 一、把握变革节点 创领产…...
全面解析 classification_report:评估分类模型性能的利器
解读 classification_report 的使用:评估分类模型性能的关键工具 在机器学习中,分类任务是最常见的应用场景之一。无论是垃圾邮件过滤、图像识别还是情感分析,分类模型的性能评估都是至关重要的一步。而 classification_report 是 Scikit-le…...
Qt案例 使用QFtpServerLib开源库实现Qt软件搭建FTP服务器,使用QFTP模块访问FTP服务器
本以为搭建和访问FTP服务器的功能已经是被淘汰的技术了,只会在学习新技术的时候才会了解学习学习,WinFrom版本,和windows Api版本访问FTP服务器的功能示例也都写过。没想到这次会在项目中再次遇到, 这里记录下使用Qt开源库QFtpSer…...
图像后处理记录
图像后处理记录 ocr后处理记录 opencv裁剪 编译命令 cmake -S . -B build-x64 -DBUILD_LIST"core,imgproc,imgcodecs,highgui" -DBUILD_SHARED_LIBSOFF -DBUILD_opencv_appsOFF -DBUILD_opencv_jsOFF -DBUILD_ANDROID_PROJECTSOFF -DBUILD_ANDROID_EXAMPLESOFF -…...
解决element中的el-anchor链接被作为路由跳转导致页面404
解决element中的el-anchor链接被作为路由跳转导致页面404 问题: 在使用elementPlus时,el-anchor-link中的href被识别为路由进行跳转,导致不能正常跳转到锚点,且页面显示404。 解决:自定义方法解决 <!--添加hand…...
Mapreduce中maven打包
MapReduce是一个分布式运算程序的编程框架,是用户开发“基于Hadoop的数据分析应用”的核心框架。 MapReduce核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的分布式运算程序(例如:jar包),并发运行在…...
C++初阶——string的使用(下)
C初阶——string的使用(下) 一、string类对象的容量操作 对于string的容量操作,我们可以通过顺序表来理解,顺序表是通过动态数组来实现的,在数据结构专栏的第一篇就是顺序表的详细讲解,链接如下ÿ…...
AIGC vs 人类创作者:是竞争还是协作?
AIGC vs 人类创作者:是竞争还是协作? 随着人工智能技术的飞速发展,特别是生成式AI(AIGC, AI-Generated Content)的崛起,越来越多的领域开始出现AI的身影。从文本创作、图像生成到音乐制作,AIGC…...
Stable Baselines3 结合 gym 训练 CartPole 倒立摆
视频讲解: Stable Baselines3 结合 gym 训练 CartPole 倒立摆 今天介绍下stable_baselines3和gym,可以方便实现DL的实现,应用在机械臂catch、reach等场景 测试代码仓库:https://github.com/LitchiCheng/DRL-learning.git https:…...
ctfshow web8
前言 学习内容:简单的盲注脚本的书写 web8 这个题目题目手动注入很麻烦 主要是他过滤了 union 空格和 过滤了union的解决方法 1、使用盲注(报错注入和盲注) 2、使用时间盲注 3、堆叠注入 盲注脚本的书写 首先他是有注入点的 然后熟悉requests包的使用 …...
Linux程序地址空间
目录 研究背景 程序地址空间回顾 来段代码感受一下 进程地址空间 Linux2.6内核进程调度队列 一个CPU拥有一个runqueue 优先级 活跃队列(只出不进) 过期队列(只进不出) active指针和expired指针 总结 研究背景 Linux内核版本&#…...
破茧成蝶:阿里云应用服务器让传统 J2EE 应用无缝升级 AI 原生时代
丝滑升级拥抱大模型:详解AI时代的应用智能化升级路径 破茧成蝶:阿里云应用服务器让传统 J2EE 应用无缝升级AI原生时代 ——十年代码无需重写,三步开启智能化跃迁 作者:孤弋、孚阳 序幕:一场跨越 20 年的技术对话 在杭…...
游戏引擎学习第240天:将渲染器移至第三层
这节又枯燥又无聊简直了 回顾并为今天的内容做铺垫 昨天我们说到,想对渲染器和平台层的集成方式做一些修改。我们之前简单讲了一下修改的目的:我们希望游戏本身不再直接调用 OpenGL 的渲染代码,而是只生成一组渲染指令缓冲区,然…...
2025.04.23华为机考第三题-300分
📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ 03. 时空旅行者的最优路径 问题描述 A先生是一名时空旅行者,他可以在不同的时空点之间穿梭。每次从一个时空点跳跃到另一个时空点需要消耗一个时间单位。在每个时空点,都有一些特…...
Kafka 保证多分区的全局顺序性的设计方案和具体实现
Kafka 本身无法直接保证多分区的全局顺序性,因为分区设计旨在并行处理以提升吞吐量。 要实现多分区的顺序性,可尝试通过以下方法在系统层面或业务逻辑上解决: 一、方案设计 单一分区路由(还是将消息发送到同一分区)&a…...
数据结构初阶:二叉树(四)
概述:本篇博客主要介绍链式结构二叉树的实现。 目录 1.实现链式结构二叉树 1.1 二叉树的头文件(tree.h) 1.2 创建二叉树 1.3 前中后序遍历 1.3.1 遍历规则 1.3.1.1 前序遍历代码实现 1.3.1.2 中序遍历代码实现 1.3.1.3 后序遍历代…...
华为开发岗暑期实习笔试(2025年4月16日)
刷题小记: 第一题怀疑测试样例不完整,贪心法不应该能够解决该题。第二题使用0-1BFS解决单源最短路径的问题,往往搭配双端队列实现。第三题是运用动态规划解决最大不重叠子区间个数的问题,难点在于满足3重判断规则,所需…...
第一篇:Django简介
第一篇:Django简介 文章目录 第一篇:Django简介一、纯手写一个简易版的web框架1、软件开发架构2、HTTP协议3、简易的socket服务端4、wsgiref模块5、动静态网页6、后端获取当前时间展示到html页面上7、字典数据传给html文件8、数据从数据库中获取的展示到…...
2025年渗透测试面试题总结-拷打题库13(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库13 一、GitHub等三方敏感信息泄漏防御 二、业务逻辑漏洞技术规避 …...
(09)Vue脚手架的使用(Vite、vue-cli、create-vue)
本系列教程目录:Vue3Element Plus全套学习笔记-目录大纲 文章目录 第3章 Vue脚手架3.1 vite3.3.1 Vite使用1)创建Vite项目2)Vite项目打包 3.1.2 组件化开发3.1.4 Vite工程运行原理1)分析main.js2)自定义根组件 3.2 vue…...
Unity 将Excel表格中的数据导入到Mysql数据表中
1.Mysql数据表users如下: 2.即将导入的Excel表格如下: 3.代码如下: using System; using System.Data; using System.IO; using Excel; using MySql.Data.MySqlClient; using UnityEngine; using UnityEditor;public class ImportExcel {// …...
【QT】信号与槽中多个按钮(pushbutton)共用一个槽函数的两种实现方式
两种方法的对比 方法1:sender() 优点:代码简洁,无需额外参数 缺点:依赖运行时类型转换,安全性较低 适用场景:简单场景,少量按钮 方法2:Lambda (推荐) 优点:安全直观&…...