opendir\readdir等 lseek#includeunistd.h off_t lseek(int fd,off_t offset,int whence);功能修改文件的读写指针位置仅移动指针不会读写数据也不会改变文件大小参数含义fd文件描述符open 打开得到offset偏移量off_t类型长整型可正可负whence参考基点3 个宏SEEK_SET从文件开头开始偏移SEEK_CUR从当前指针位置开始偏移SEEK_END从文件末尾开始偏移offset正数向后移负数向迁移0代表不做额外偏移返回值成功返回当前读写指针距离文件开头的字节偏移量失败返回-1并设置errno常用实例1.定位到文件开头lseekfd,0,SEEK_SET;2.定位到文件末尾lseek(fd,0,SEEK_END);3.获取文件总大小经典用法把指针挪到文件末尾lseek返回值就是文件字节数off_t lenlseek(fd,0,SEEK_END);4.向后偏移N字节从当前位置lseek(fd,100,SEEK_CUR);重点1.lseek只移动指针不改变文件实际大小2.不能对管道、socket使用lseek,会返回-1报错3.off_t是有符号长整型打印要用%lld,不要直接用%d//跳到目标大小-1字节处 lseek(fd, target_size - 1, SEEK_SET); write(fd, ch, 1); //必须写1字节文件才扩容产生空洞#includedirent.h #includesys/types.h DIR *opendir(const char *name);功能打开一个指定的目录返回一个关联的目录流指针DIR*后续用readdir读目录内容都靠这个指针。参数name要打开目录名相对路径或绝对路径返回值成功返回目录流指针DIR*失败返回NULLeg打开一个目录并判断是否成功#includestdio.h #includesys/types.h #includeditent.h main() { if(argc!2) { printf(Usage:%sdir name\n,argv[0]); return -1; } DIR *dpopendir(argv[1]); if(dpNULL) { printf(opendir fail\n); return -1; } printf(目录打开成功\n); closedir(dp); return 0; }READDIR-------------读目录#include dirent.h struct dirent *readdir(DIR *dirp); struct dirent{ ino_t d_ino; //inode编号 off_t d_off; //下一个目录项的偏移 unsigned short d_reclen; //当前记录长度 unsigned char d_type; //文件类型 char d_name[256]; //文件名最常用 };宏含义DT_REG普通文件DT_DIR目录DT_LNK符号链接DT_BLK块设备DT_CHR字符设备DT_FIFO管道DT_SOCK套接字DT_UNKNOWN未知eg:遍历目录打印所有非隐藏文件名#include stdio.h #include sys/types.h #include dirent.h main() { if(argc!2) { printf(Usage:%sdir name\n,argv[0]); return -1; } struct dirent *pdirNULL; while(1) { pdirreaddir(dp); if(pdirNULL) { break; } if(pdir-d_name[0]!-) { printf(%S\n,pdir-d_name); } } closedir(dp); return 0; }CLOSEDIR-------------关闭目录#include sys/types.h #include dirent.h int closedir(DIR *dirp);功能关闭一个已经打开的目录流释放相关资源。和opendir配对使用打来了就必须关闭参数dirp要关闭的目录流指针opendir的返回值返回值成功0失败-1注意事项不要多次释放同一个DIR*只能closedir一次重复关闭会导致未定义行为程序结束前必须关闭所有打开的目录否则会资源泄露eg:完整的 打开 - 读 - 关闭 流程统计目录下文件个数#includestdio.h #includesys/types.h #includedirent.h main() { if(argc!2) { printf(Usage:%sdir name\n,argv[0]); return -1; } DIR *dpopendir(argv[1]); if(dpNULL) { printf(opendir fail\n); return -1; } struct dirent *pdirNULL; int count0; while(1) { pdirreaddir(dp); if(pdirNULL) { break; } if(pdir-d_name[0]!!-) { count; } } printf(目录下共有%d个非隐藏文件\ncount); int retclosedir(dp); if(ret-1) { printf(closedir fail\n); return -1; } printf(目录已关闭\n); return 0 }CHDIR----切换当前工作目录#includeunistd.h int chdir(const char *path);功能改变当前程序的工作目录效果等同于shell里的cd命令参数path:目标路径可以是相对路径如../、./dir或绝对路径/tmp、/home/user注意只影响当前程序chdir只改变这个 C 程序内部的工作目录不会改变你终端 shell 的路径程序一退出就失效。不能用~C 语言不会解析波浪号~~是 shell 的语法必须写完整绝对路径#include stdio.h //printf、fopen、fclose #include unistd.h //chdir int main(void) { //切换当前工作目录到 /tmp //chdir 相当于 shell 的 cd /tmp int ret chdir(/tmp); //切换失败返回 -1 if (ret -1) { printf(chdir fail\n); return -1; } printf(已切换到 /tmp 目录\n); //在当前工作目录现在是 /tmp创建一个文件 //因为已经 chdir 到 /tmp所以文件会创建在 /tmp 下 //而不是程序原来所在的目录 FILE *fp fopen(chdir_test.txt, w); if (fp ! NULL) { printf(文件 chdir_test.txt 已创建在 /tmp 下\n); fclose(fp); //关闭文件 } return 0; }GETCWD---------获取当前工作目录#include unistd.h char *getcwd(char *buf, size_t size);功能获取当程序的工作目录的绝对路径效果等同于 shell 里的pwd命令。参数buf用来存放路径字符串的缓冲区首地址你自己定义的字符数组size缓冲区的大小最多能存多少字节返回值成功返回buf的首地址也就是路径字符串的指针失败返回NULL缓冲区太小装不下路径例子获取当前路径切换目录后再获取一次对比变化#include stdio.h //printf #include unistd.h //getcwd、chdir int main(void) { //定义缓冲区用来存放路径字符串 //路径一般不会太长1024 足够用 char buf[1024]; //1.获取切换前的当前工作目录 //把当前路径写入 buf最多写 sizeof(buf) 个字节 char *p getcwd(buf, sizeof(buf)); if (p NULL) { printf(getcwd fail\n); return -1; } printf(切换前路径%s\n, buf); //2.切换工作目录到 /tmp int ret chdir(/tmp); if (ret -1) { printf(chdir fail\n); return -1; } //3.再次获取当前工作目录验证已经切换 getcwd(buf, sizeof(buf)); printf(切换后路径%s\n, buf); return 0; }MKDIR---------创建目录#include sys/stat.h #include sys/types.h int mkdir(const char *pathname, mode_t mode);功能创建一个新的目录文件相当于 shell 里的mkdir命令。参数pathname要创建的目录路径相对路径或绝对路径mode目录权限八进制数如0777、0755、0666返回值成功返回0失败返回-1目录已存在 / 上级目录不存在 / 权限不足重要注意事项mode 必须写八进制前面加0写777是十进制完全错误。权限 mode ~umask系统会用 umask 掩码去掉一些权限。例如 mode 写0777umask 默认0002实际权限是0775。目录必须有 x执行权限才能cd进入所以目录权限一般用07xx不要用0666。不能一次性创建多级目录比如mkdir(a/b/c, 0777)如果a或b不存在就直接失败。例子在当前目录下创建一个 dir123 目录并验证#include stdio.h //printf #include sys/stat.h //mkdir #include sys/types.h //mode_t 等类型 int main(void) { //创建目录 dir123指定权限 0775 //0775 rwxrwxr-x所有者和组可读写执行其他只读执行 int ret mkdir(dir123, 0775); //创建失败 if (ret -1) { printf(mkdir fail目录可能已存在或上级目录不存在\n); return -1; } printf(目录 dir123 创建成功\n); //再次尝试创建同名目录会失败因为已经存在 ret mkdir(dir123, 0775); if (ret -1) { printf(再次创建失败目录已存在\n); } return 0; }rmdir---------删除空目录#include unistd.h int rmdir(const char *pathname);功能删除一个空目录相当于 shell 里的rmdir命令。参数pathname要删除的目录路径返回值成功返回0失败返回-1重要注意事项只能删除空目录目录里面不能有任何文件或子目录否则删除失败。想删除非空目录需要先递归删除里面的内容C 标准库没有直接的rm -rf。只能删目录不能删普通文件删普通文件用unlink后面会讲。不能删除.当前目录和..上级目录。例子创建目录 → 验证非空删除失败 → 清空后删除成功#include stdio.h //printf、fopen、fclose #include sys/stat.h //mkdir #include unistd.h //rmdir int main(void) { //1.先创建一个测试目录 testdir int ret mkdir(testdir, 0775); if (ret -1) { printf(mkdir fail\n); return -1; } printf(目录 testdir 创建成功\n); //2.在目录里创建一个文件让目录变成非空 FILE *fp fopen(testdir/a.txt, w); if (fp ! NULL) { printf(在 testdir 里创建了 a.txt\n); fclose(fp); } //3.尝试删除非空目录会失败 ret rmdir(testdir); if (ret -1) { printf(删除失败testdir 不是空目录里面有 a.txt\n); } //4.先删掉目录里的文件用 remove 或 unlink remove(testdir/a.txt); printf(已删除 testdir 里的 a.txt现在目录空了\n); //5.再次删除空目录这次成功 ret rmdir(testdir); if (ret 0) { printf(删除成功testdir 已被删除\n); } return 0; }shell 命令C 函数区别rmdir dirrmdir(dir)只能删空目录rm -rf dir无直接对应需要自己递归删除rm fileremove(file)/unlink(file)删除普通文件8.STAT--------获取文件属性#include sys/types.h #include sys/stat.h #include unistd.h int stat(const char *path, struct stat *buf);功能获取指定文件的全部属性存入struct stat结构体。ls -l显示的所有信息类型、权限、大小、时间等都来自这个函数。参数path文件路径相对路径或绝对路径buf保存属性的结构体变量的首地址要自己定义变量然后传变量名返回值成功返回0失败返回-1文件不存在 / 权限不足struct stat 重点字段struct stat { ino_t st_ino; // inode 编号 mode_t st_mode; // 文件类型 权限最核心位域 nlink_t st_nlink; // 硬链接数 uid_t st_uid; // 所有者用户ID gid_t st_gid; // 所属组ID off_t st_size; // 文件大小字节 time_t st_atime; // 最后访问时间 time_t st_mtime; // 最后修改时间最常用 time_t st_ctime; // 最后状态改变时间 };st_mode位域st_mode是一个整数不同位段代表不同含义位段宏作用文件类型S_IFMT掩码st_mode S_IFMT判断是普通文件 / 目录 / 链接等所有者权限S_IRUSR / S_IWUSR / S_IXUSR与运算判断 r w x组权限S_IRGRP / S_IWGRP / S_IXGRP与运算判断 r w x其他权限S_IROTH / S_IWOTH / S_IXOTH与运算判断 r w xeg:用 stat 获取文件属性并打印#include stdio.h //printf #include sys/types.h //stat 需要 #include sys/stat.h //stat、struct stat、S_IFMT、S_IFREG #include unistd.h //stat 需要 #include time.h //localtime、struct tm int main(int argc, const char *argv[]) { //判断参数./a.out 文件名 if (argc ! 2) { printf(Usage: %s file name\n, argv[0]); return -1; } //定义 stat 结构体变量用来接收文件属性 struct stat f_info; //调用 stat把 argv[1] 文件的属性写入 f_info //注意第二个参数传地址 f_info int ret stat(argv[1], f_info); if (ret -1) { printf(stat fail\n); return -1; } //1.打印 inode 编号 printf(inode号%ld\n, (long)f_info.st_ino); //2.打印硬链接数 printf(硬链接数%ld\n, (long)f_info.st_nlink); //3.打印文件大小字节 printf(文件大小%ld 字节\n, (long)f_info.st_size); //4.判断文件类型st_mode S_IFMT 提取类型位 if ((f_info.st_mode S_IFMT) S_IFREG) { printf(文件类型普通文件\n); } else if ((f_info.st_mode S_IFMT) S_IFDIR) { printf(文件类型目录\n); } else if ((f_info.st_mode S_IFMT) S_IFLNK) { printf(文件类型符号链接\n); } //5.判断所有者是否有读权限与运算 if (f_info.st_mode S_IRUSR) { printf(所有者有读权限\n); } else { printf(所有者无读权限\n); } //6.打印最后修改时间st_mtime 是时间戳用 localtime 转换 struct tm *tp localtime(f_info.st_mtime); printf(最后修改%d年%d月%d日 %02d:%02d\n, tp-tm_year 1900, //年份要加1900 tp-tm_mon 1, //月份0~11加1 tp-tm_mday, //几号 tp-tm_hour, //小时 tp-tm_min); //分钟 return 0; }序号函数作用对应 shell 命令1opendir打开目录—2readdir读目录条目—3closedir关闭目录—4chdir切换工作目录cd5getcwd获取当前路径pwd6mkdir创建目录mkdir7rmdir删除空目录rmdir8stat获取文件属性ls -l底层