Linux文件操作

article/2025/10/11 23:15:36

目录

  • 一、系统api与库函数的关系
  • 二、open和close函数介绍
    • 2.1 open方法介绍
    • 2.2 close方法介绍
  • 三、open/create函数创建文件时的权限设置
  • 四、read和write函数的介绍和使用
    • 4.1 read函数介绍
    • 4.2 write函数介绍
    • 4.3 如何使用
  • 五、lseek函数的介绍和使用
    • 5.1 介绍
    • 5.2 如何使用
  • 六、阻塞和非阻塞相关概念
    • 6.1 fcnl函数
  • 七、Linux最大文件打开数
    • 7.1 修改单个进程的最大文件句柄
    • 7.2 修改系统所有进程的文件局柄
  • 八、stat函数介绍和使用
    • 8.1 通过stat函数实现ll命令的功能
    • 8.2 stat与lstat的区别
  • 九、access和truncate函数使用
    • 9.1 access函数
    • 9.2 truncate函数
  • 十、链接函数的使用
    • 10.1 link(硬链接)
    • 10.2 symlink(软/符号链接)
    • 10.3 readlink
    • 10.4 unlink
  • 十一、chown和rename函数的使用
    • 11.1 chown
    • 11.2 rename
  • 十二、 chdir和getcwd函数的使用
    • 12.1 chdir
    • 12.2 getcwd
  • 十三、mkdir函数的使用
  • 十四、rmdir/opendir/readdir/closedir函数的使用
    • 14.1 rmdir
    • 14.2 opendir
    • 14.3 readdir
    • 14.4 closedir
    • 14.5 案例-递归统计子目录中的普通文件个数
  • 十五、errno说明
  • 十六、dup/dup2函数的使用

一、系统api与库函数的关系

linux系统默认启动程序时会打开stdin/stdout/stderr ,我们可以直接使用通过<unistd.h>库中的close方法可以指定关闭上面的标准输入/输出和错误, 例如close(1)表示关闭标准输出.

通过open命令可以打开一个输出,此时如果标准输出关闭了,那么open命令可以替换标准输出.
通过<stdio.h>库中的fflush方法可以刷新标准输入和输出的缓存区buffer,例如 fflush(stdout);

二、open和close函数介绍

通过man 2 open/close可以查看open/close函数的用法,或者在编写代码的时候,在命令模式下光标移动到函数名上,按下2(表示第2章) 再按下K 就可以跳到这个函数的介绍了.

2.1 open方法介绍

在这里插入图片描述
open方法表示打开一个文件描述符,其中pathname是文件名

flags的必选项(必选项只能选其中一个):

  • O_RDONLY :read-only
  • O_WRONLY:write-only
  • O_RDWR:read/write

flags的可选项有:

  • O_APPEND(追加)
  • O_CREAT(若文件不存在则创建)
  • O_EXCL(必须和O_CREAT一起使用,若文件存在的报错)
  • O_NONBLOCK(非阻塞)

mode:表示权限位,最终是(mode & ~umask)

可选项是可以和必选项结合使用的

返回值:是返回最小的可用的的文件描述符,假设存在stdin/stdout/stderr都存在,那么open返回最小是3.因为0,1,2被占用了.失败时返回-1.

案例-通过open简单实现一个touch命令的功能

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>int main(int argc,char* args[])
{if(argc !=2){printf("./touch filename\n");return -1;}int fd = open(args[1],O_RDONLY|O_CREAT,0666);// 0666是mode,后面会介绍close(fd);return 0;
}

在这里插入图片描述

2.2 close方法介绍

在这里插入图片描述
close表示关闭一个文件描述符.返回值,成功返回0,失败返回-1.

三、open/create函数创建文件时的权限设置

首先了解一下 umask 命令,该命令用来设置限制新文件权限的掩码。当新文件被创建时,其最初的权限由文件创建掩码决定。简单地来说,umask和open()及creat()函数的权限码(mode_t mode参数)共同决定你的新建文件的权限。具体关系为mode & ~umask。

下面通过简单的程序来验证它们之间的关系。
由于open()和creat()创建文件,结果一致,我们直接采用creat()函数:

#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>int main()
{if(creat("1.log",0777)<0){printf("创建文件失败!\n");}else{printf("创建文件成功!\n");}return 0;
}

编译执行后,查看生成文件1.log的权限
在这里插入图片描述
权限是775,这和我们的期望777不符,为什么呢? 这是因为creat和open创建文件时的权限是 mode & ~umask的结果, mode虽然是0777,但是普通用户的umask是0002,如下所示:
在这里插入图片描述
所以~umask (umask取反,也就是0002取反)的结果是7775, 套公式mode & ~umask 也就是0777 & 7775 的结果是0775, 也就是1.log文件的最终权限是rwx rwx r-x

那么如何避免umask的影响呢?
我们可以使用umask函数,将值设置为0000,那么~umask的值就变成7777了, 由于7的二进制是111, 不会影响&操作的结果. 将上面的代码修改如下:

#include<stdio.h>
#include<fcntl.h>
#include<sys/stat.h>int main()
{umask(0000);//将umask的值临时修改为0000,这个不会修改系统的umask默认值.if(creat("1.log",0777)<0) //临时修改了umask值后,设置的最终权限结果就是0777{printf("创建文件失败!\n");}else{printf("创建文件成功!\n");}return 0;
}

重新编译执行,查看1.log的权限就变成了777了
在这里插入图片描述
当然如果只是创建普通文件的话,没必要添加执行权限,一般就是666权限就可以了.也就是rw-rw-rw-

umask的值表示的权限是u/g/o所"不具备"的权限,它是Linux的默认权限,root用户是0022,表示root用户创建文件或者文件夹时,g(所属组)和o(其他组)将不具备w权限,普通用户是0002,表示普通用户创建目录或者文件时,o(其他组)将不具备w权限.
所以,有了umask的限制之后,我们通过库函数设置的权限就可以符合Linux下使用命令创建文件的权限效果一样.例如普通用户在Linux上使用touch命令创建的文件的权限就是664, 那么我们使用库函数创建文件就可以将mode设置为0666,这样0666与7775的结果就是0664 ,6和5的二进制&的结果就是4.
当然,如果你觉得计算太麻烦, 那么我们其实根据umask规则也可以知道,普通用户的o是没有w权限,所以mode设置为0666的最后结果就是0664 (0666-0002)
除非你需要明确添加w权限,那么你可以通过umask函数临时去掉限制.

四、read和write函数的介绍和使用

4.1 read函数介绍

read函数需要导入这些头文件

#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

函数原型如下
在这里插入图片描述
fd:文件描述符
buf:缓冲区
count:缓冲区大小
ssize_t:返回值,返回读取的实际字节长度. -1表示失败, 0 表示读到文件末尾

4.2 write函数介绍

在这里插入图片描述
fd:文件描述符
buf:缓冲区
count:缓冲区大小,注意字符串不需要考虑’\0’所占的1个字节,例如"abc"字符串,对应的count就是3
ssize_t:返回值,成功返回写入的实际字节数, -1表示失败, 0表示未写入.

注意:write完后,指针的标记是停留在最后一个字节的,此时如果直接用read来读是没法读取内容的.

4.3 如何使用

例如实现一个cat命令的功能

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>int main(int argc,char* args[])
{if(argc !=2){printf("usage: ./cat filename");return -1;}int fd = open(args[1],O_RDONLY);char buf[1024] = {0};int len = -1;while((len = read(fd,buf,sizeof(buf)))!=0){//将读取的内容输出到屏幕write(STDOUT_FILENO,buf,len); //其中STDOUT_FILENO是stdout的宏定义,值是1,表示标准输出}close(fd);return 0;
}

编译后,执行效果如下:
在这里插入图片描述

五、lseek函数的介绍和使用

5.1 介绍

作用类似fseek函数,用于设置当前文件读或者写的位置,参数介绍如下:
在这里插入图片描述
fd:文件描述符
offset:偏移量,通常是0,结合whence来使用,用来定位到文件的开头,文件的当前和文件的结束位置.
whence: 表示从什么位置开始设置,有3个值,

  • SEEK_SET(文件开头位置)
  • SEEK_CUR(文件当前读写的位置)
  • SEEK_END(文件结束位置)

off_t :成功返回当前位置到开始位置的长度(字节数),失败返回-1.

5.2 如何使用

如果要实现open() … write()… read()…close() 方式来操作同一个文件的话,那么write()和read()之间就需要用到lseek()了.因为write()完后,标记位置的指针已经指向文件末尾了,此时需要用lseek()重置到开头位置,然后read()才能读到内容.

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>int main(int argc, char* args[])
{int fd = open("./test2.txt",O_RDWR|O_CREAT,0666); //打开./test2.txt,若不存在则创建//先写,输出11个字节,包括了\nwrite(fd,"helloworld\n",11);//重置到开始位置lseek(fd,0,SEEK_SET);//后读char buf[1024] = {0};int len = read(fd,buf,sizeof(buf));if(len){	//显示到屏幕 fd=STDOUT_FILENOwrite(STDOUT_FILENO,buf,len);}//最后关闭close(fd);return 0;
}

在这里插入图片描述

另外使用lseek还能用来获取文件的大小, 因为lseek的返回值就是从文件开头到lseek定位的位置之间的长度(字节数), 假设直接调用lseek移动到文件末尾,那么返回的就是文件的大小了.
例如:

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>int main(int argc,char* args[])
{if(argc != 2){printf("Usage: ./len filename");return -1;}int fd = open(args[1],O_RDONLY);int len = lseek(fd,0,SEEK_END);printf("file len is: %d\n",len);close(fd);
}

编译执行,查看文件的大小,刚好和ll命令查看的一样
在这里插入图片描述

六、阻塞和非阻塞相关概念

当使用read函数读设备或者管道或者网络的时候就会出现阻塞现象.
下面通过输入输出设备来模拟, 对应的位置是/dev/tty

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>int main()
{char buf[1024] = {0};int len = 0;int fd = open("/dev/tty",O_RDWR); // 设置读写来源于设备的输入输出while(1){int len = read(fd,buf,sizeof buf); //由于读取的是设备,所以read会阻塞在此,直到用户输入内容if(len){printf("buf is : %s\n",buf);}printf("haha\n");//这句话虽然在while true里面,但是由于read阻塞了,所以并不会一直输出}close(fd);return 0;
}

从结果可以看出,输入内容后,read才会走下一步,然后再次循环又停在了read函数处等等用户继续输入,这种现象就是阻塞
在这里插入图片描述
如果不想被阻塞该怎么处理?
只需要将read的flag新增一个O_NONBLOCK即可,如下所示:

int fd = open("/dev/tty",O_RDWR|O_NONBLOCK);

或者使用<fcntl.h>中的fcntl函数.

6.1 fcnl函数

在这里插入图片描述
cmd参数可选有:

  • F_GETFL ,如果用这个那么可以省略第3个参数
  • F_SETFL ,如果用这个那么第三个参数必须是int类型

用法如下:

#include<stdio.h>
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>int main()
{char buf[1024] ={0};int len = 0;int fd = open("/dev/tty",O_RDONLY);//1.先获取标记int flags = fcntl(fd,F_GETFL);//2.添加非阻塞标记flags |= O_NONBLOCK;//3.重新设置标记fcntl(fd,F_SETFL,flags);while(1){int len = read(fd,buf,sizeof buf);if(len){printf("buf is:%s\n",buf);}printf("haha\n");}close(fd);return 0;
}

七、Linux最大文件打开数

在Linux下有时会遇到Socket/File : Can’t open so many files的问题。其实Linux是有文件句柄限制的,而且Linux默认一般都是1024(阿里云主机默认是65535)。在生产环境中很容易到达这个值,因此这里就会成为系统的瓶颈。

使用ulimit -a 或者 ulimit -n
在这里插入图片描述
open files (-n) 1024 是linux操作系统对一个进程打开的文件句柄(文件描述符表)数量的限制(也包含打开的套接字数量。

7.1 修改单个进程的最大文件句柄

通过下面的命令可以

ulimit -SHn 10000

其实ulimit 命令身是分软限制和硬限制,加-H就是硬限制,加-S就是软限制。默认显示的是软限制,如果运行ulimit 命令修改时没有加上-H或-S,就是两个参数一起改变。

软限制和硬限制的区别?

硬限制就是实际的限制,而软限制是警告限制,它只会给出警告。

要想ulimits 的数值永久生效,必须修改配置文件/etc/security/limits.conf
在该配置文件中添加

* soft nofile 65535   
* hard nofile 65535  echo "* soft nofile 65535"  >> /etc/security/limits.confecho "* hard nofile 65535"  >> /etc/security/limits.conf

其中 * 表示所用的用户

7.2 修改系统所有进程的文件局柄

上面的修改只是对一个进程打开的文件句柄数量的限制,我们还需要设置系统的总限制才可以。

假如,我们设置进程打开的文件句柄数是1024 ,但是系统总线制才500,所以所有进程最多能打开文件句柄数量500。从这里我们可以看出只设置进程的打开文件句柄的数量是不行的。所以需要修改系统的总限制才可以。

echo 6553560 > /proc/sys/fs/file-max

上面是临时生效方法,重启机器后会失效;

永久生效方法:

修改 /etc/sysctl.conf, 加入

fs.file-max = 6553560重启生效

通过下面代码可以验证这个文件句柄的限制

#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>int main()
{int num = 0;char filename[128] = {0};while(1){sprintf(filename,"temp_%04d",num++); //%04表示不够4位用0补齐.if(open(filename,O_RDONLY|O_CREAT,0666)<0){perror("open error");break;}}return 0;
}

如下图所示一共生成了temp_0000~temp_1020个文件,也就是1021个,为啥不是1024呢,因为文件描述符表中0 ,1 ,2 默认打开程序的时候就被stdin/stdout/stderr占用了. 所以加上这3个刚好就是1024个.
在这里插入图片描述

八、stat函数介绍和使用

在这里插入图片描述
这个函数用于获取文件的信息,主要指文件的属性,在C基础(七)文件操作也有介绍过

参数:

  • pathname:文件名
  • statbuf:传出参数,需要外部定义一个struct stat类型的变量,然后传入地址.

返回值:
成功返回0,失败返回-1

stat结构体的成员信息如下:
在这里插入图片描述
如何使用?

#include<stdio.h>
#include<unistd.h>
#include<sys/stat.h>
#include<sys/types.h>int main(int argc,char* args[])
{if(argc !=2){printf("Usage: ./stat filename\n");return -1;}struct stat st; //定义一个结构体//调用stat函数,参数1是文件名,参数2是上面定义的结构体的地址,函数内部会将获取的信息封装到st变量中stat(args[1],&st); return 0;
}

编译源文件

gcc -o stat statUsage.c -g

然后通过gdb调用启动程序查看statUsage.c文件的stat的内容.
在这里插入图片描述
对应的内容就是stat命令中的内容:
在这里插入图片描述

8.1 通过stat函数实现ll命令的功能

首先需要介绍如何获取用户名,通过getpwuid函数实现
在这里插入图片描述
需要传递uid参数,用户id,返回的是一个passwd的结构体指针
在这里插入图片描述
然后是获取组信息,通过getgrgid函数来实现
在这里插入图片描述
需要传递gid参数,组id,返回的是一个group的结构体指针
在这里插入图片描述
然后通过localtime函数可以查看本地时间
在这里插入图片描述
返回的是tm结构体
在这里插入图片描述
接下来就是要实现下图效果的编码了
在这里插入图片描述

#include<stdio.h>
#include<sys/stat.h>
#include<sys/types.h>
#include<unistd.h>
#include<fcntl.h>
#include<string.h>
#include<time.h>
#include<pwd.h>
#include<grp.h>int main(int argc ,char * args[])
{if(argc !=2){printf("Usage: ./ll filename");}struct stat st;stat(args[1],&st);char stmode[11] = {0};memset(stmode,'-',10);//文件类型if(S_ISREG(st.st_mode)) stmode[0]='-';//普通文件if(S_ISDIR(st.st_mode)) stmode[0]='d';//文件夹if(S_ISCHR(st.st_mode)) stmode[0]='c';//字符设备文件if(S_ISBLK(st.st_mode)) stmode[0]='b';//块设备文件if(S_ISFIFO(st.st_mode))stmode[0]='p';//管道文件if(S_ISLNK(st.st_mode))stmode[0]='l';//软连接文件if(S_ISSOCK(st.st_mode))stmode[0]='s';//socket文件//权限描述 userif(st.st_mode & S_IRUSR) stmode[1] = 'r';if(st.st_mode & S_IWUSR) stmode[2] = 'w';if(st.st_mode & S_IXUSR) stmode[3] = 'x';//权限描述符 groupif(st.st_mode & S_IRGRP) stmode[4] = 'r';if(st.st_mode & S_IWGRP) stmode[5] = 'w';if(st.st_mode & S_IXGRP) stmode[6] = 'x';//权限描述符 otherif(st.st_mode & S_IROTH) stmode[7] = 'r';if(st.st_mode & S_IWOTH) stmode[8] = 'w';if(st.st_mode & S_IXOTH) stmode[9] = 'x';//通过localtime函数获取时间struct tm *filetm = localtime(&st.st_atim.tv_sec);char timebuf[20]={0};sprintf(timebuf,"%d月   %d %02d:%02d",filetm->tm_mon+1,filetm->tm_mday,filetm->tm_hour,filetm->tm_min);//通过getpwuid getgrgid函数获取用户id和组idprintf("%s %ld %s %s %ld %s %s\n",stmode,st.st_nlink,getpwuid(st.st_uid)->pw_name,getgrgid(st.st_gid)->gr_name,st.st_size,timebuf,args[1]);return 0;
}

编译执行,效果如下,和ll命令完全一样.
在这里插入图片描述

8.2 stat与lstat的区别

stat遇到软连接会穿透查看源文件的信息,包括文件真实大小,而lstat则不会,查看软连接时显示的是软连接的大小.软连接的大小通常是固定的. 系统的ll命令的效果就是没有穿透的.例如:
在这里插入图片描述
ll命令查看t1.c软连接显示是7个字节, 而用我上面写的Myll.c程序查看的是335,因为Myll.c用的是stat实现的.

九、access和truncate函数使用

9.1 access函数

用于判断当前用户是否具有读/写/执行的权限,以及判断文件是否存在

mode参数有:

  • R_OK :判断是否可读
  • W_OK:判断是否可写
  • X_OK:判断是否可执行
  • F_OK:判断文件是否存在

返回值:
文件存在或者存在某权限返回0 ,否则返回-1

#include<stdio.h>
#include<unistd.h>int main(int argc,char* args[])
{if(argc != 2){printf("Usage: ./access filename");return -1;}if(access(args[1],R_OK) ==0)printf("%s read ok\n",args[1]);if(access(args[1],W_OK)==0)printf("%s write ok\n",args[1]);if(access(args[1],X_OK)==0)printf("%s exe ok\n",args[1]);if(access(args[1],F_OK)==0)printf("%s file exist\n",args[1]);return 0;
}

编译执行结果如下:
在这里插入图片描述

9.2 truncate函数

用于截断文件
在这里插入图片描述
参数

  • path: 文件名 length:
  • 长度,如果长度大于原文件那么会扩展,用其他符号填充,如果小于原文件,则截断为length长度.

返回值
成功返回0,失败返回-1

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>int main(int argc,char* args[])
{if(argc !=3){printf("Usage: truncate filename length\n");return -1;}truncate(args[1],atoi(args[2]));return 0;
}

编译执行,可以看到hello文件的大小变成了1024字节.
在这里插入图片描述

十、链接函数的使用

10.1 link(硬链接)

制造硬链接
在这里插入图片描述
参数:

  • oldpath:原文件
  • newpath:硬链接文件

返回值
0:成功 -1:失败

10.2 symlink(软/符号链接)

制造软链接
在这里插入图片描述
参数:

  • target:原文件
  • linkpath:软连接文件

返回值
0:成功 -1:失败

10.3 readlink

用于读取软(符号)链接本身的内容,得到该链接指向的文件名
在这里插入图片描述
参数

  • pathname:软链接文件名
  • buf:缓冲区
  • bufsiz:缓冲区大小

返回值
成功返回读到的软连接的长度,失败返回-1.

10.4 unlink

删除软(符号)链接或者硬链接或者文件, 注意:unlink在删除文件的时候如果当前程序正在访问该文件,那么unlink不会立马删除该文件,而是等等程序退出的时候才去删除.
在这里插入图片描述
参数pathname: 对应的链接名字 或者原文件名

返回值
0:成功 -1:失败

#include<stdio.h>
#include<unistd.h>int main()
{//创建硬链接link("hello","hello.hard");//创建软连接symlink("hello","hello.soft");//读取软连接指向的原文件名称char buf[64]={0};readlink("hello.soft",buf,sizeof buf);printf("hello.soft链接指向的原文件名是:%s\n",buf);return 0;
}

编译执行
在这里插入图片描述
删除软硬链接和原文件

//删除硬链接
unlink("hello.hard");
//删除软链接
unlink("hello.soft");
//删除原文件
unlink("hello");

删除后再次运行上面程序输出结果如下:
在这里插入图片描述

十一、chown和rename函数的使用

11.1 chown

改变用户和组
在这里插入图片描述
参数

  • pathname:文件名
  • owner:用户id,参考/etc/passwd
  • group:组id ,参考/etc/group

11.2 rename

重命名文件
在这里插入图片描述
参数

  • oldpath:旧文件(目录)
  • newpath:新文件(目录)

返回值
成功:0 失败:-1

十二、 chdir和getcwd函数的使用

12.1 chdir

改变进程工作目录
在这里插入图片描述
参数path:对应的目标路径

返回值
成功: 0 失败-1

12.2 getcwd

获取当前进程的工作路径
在这里插入图片描述
参数

  • buf:传出参数,路径
  • size_t: buf的大小

返回值
成功返回路径的指针,失败返回NULL

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>int main()
{//切换当前进程的工作目录chdir("bbb");int fd = open("tmp",O_WRONLY|O_CREAT,0666);char* str = "到此一游\n";write(fd,str,strlen(str));//显示当前进程工作目录char buf[64] = {0};getcwd(buf,sizeof buf);printf("buf is [%s]\n",buf);return 0;
}

编译执行
在这里插入图片描述

十三、mkdir函数的使用

创建目录
在这里插入图片描述
参数

  • pathname:目录名
  • mode:权限模式,最终结果是mode & ~umask &0777, 如果目录没有可执行权限是无法进入的,所以使用这个函数创建目录时,mode通常是0777, 也就是普通用户执行后,最终权限是0775( 0777-0002)

十四、rmdir/opendir/readdir/closedir函数的使用

14.1 rmdir

删除空目录
在这里插入图片描述

14.2 opendir

打开目录
在这里插入图片描述

14.3 readdir

读取目录,参数是opendir的返回值
在这里插入图片描述
返回值是struct dirent结构体指针,返回NULL表示读到结尾
在这里插入图片描述
其中d_type=4表示目录,d_type=8(对应的宏定义是DT_REG)表示普通文件, 文件类型声明如下:

/** File types*/
#define DT_UNKNOWN       0
#define DT_FIFO          1
#define DT_CHR           2
#define DT_DIR           4 // 目录文件
#define DT_BLK           6
#define DT_REG           8 // 普通文件
#define DT_LNK          10
#define DT_SOCK         12
#define DT_WHT          14

14.4 closedir

关闭目录,参数也是opendir的返回值
在这里插入图片描述

14.5 案例-递归统计子目录中的普通文件个数

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>// 定义全局变量
int count = 0;// 计算文件数量
int DirCount(char *path)
{printf("%s\n", path);//打开目录DIR *dirp = opendir(path);if (dirp == NULL){perror("opendir err");return -1;}//打开目录成功,读取目录struct dirent *direntp = NULL;while ((direntp = readdir(dirp)) != NULL){if (direntp->d_type == DT_DIR){//如果是目录,排除. 和..目录if (strcmp(".", direntp->d_name) == 0 ||strcmp("..", direntp->d_name) == 0){continue;}//递归进入子目录char newdirname[1024] = {0};sprintf(newdirname, "%s/%s", path, direntp->d_name);DirCount(newdirname);}//统计普通文件个数if (direntp->d_type == DT_REG){count++;printf("dname:%s\n", direntp->d_name);}}//关闭目录closedir(dirp);return 0;
}int main(int argc, char *args[])
{if (argc != 2){printf("Usage: ./coutdir dirname");}DirCount(args[1]);printf("count=%d\n", count);
}

编译执行
在这里插入图片描述

十五、errno说明

记录的一些错误码和相关描述,在下面的文件中可以查看

 /usr/include/asm-generic/errno-base.h/usr/include/asm-generic/errno.h

当然你也可以在代码中通过strerror函数传入errno来获取错误描述
在这里插入图片描述

十六、dup/dup2函数的使用

在这里插入图片描述

  • dup
    用于复制文件描述符,可以用于备份
    返回值
    成功:返回新的文件描述符指向oldfd对应的文件
    失败:返回-1,设置errno

  • dup2
    重定向,让新的文件描述符指向旧的文件描述
    返回值
    成功:关闭newfd对应的文件描述符,将newfd重新指向oldfd对应的文件
    失败:返回-1,设置errno


http://chatgpt.dhexx.cn/article/v600APDW.shtml

相关文章

python文件操作(一看就懂)

python文件操作 历史遗留问题文件介绍打开文件转定义字符Python格式化字符串的替代符以及含义Python的转义字符及其含义 &#x1f495;Final~ 历史遗留问题 现在我们接着上文讲&#xff0c;如果没有看过我上篇文章的萌新朋友们可以先去看看&#xff0c;不然一会儿容易读的你满…

Linux的文件操作命令

接下来将介绍Linux中一些常用的文件操作命令&#xff0c;今天先演示五个类型的命令操作&#xff0c;内容不是特别的全&#xff0c;找的几个典型的常用的演示&#xff0c;想要全面的可以另找资料了解一下&#xff0c;推荐大家跟着敲跟着做才能加深记忆&#xff0c;祝大家学的开心…

Linux —— 文件操作

目录 1.内核提供的文件系统调用 1.1open和close 1.2标记位 1.3write和read 2.文件描述 2.1文件描述符 2.2文件描述符分配规则 3.重定向 3.1最“挫”的重定向 3.2使用系统调用 3.3重定向原理 3.4让我们的"shell"支持重定向操作 4.一切皆文件 5.缓冲区 5…

文件操作详解

1.文件的概念 文件的基本概念   所谓“文件”是指一组相关数据的有序集合。 这个数据集有一个名称&#xff0c;叫做文件名。实际上在前面的各章中我们已经多次使用了文件&#xff0c;例如源程序文件、目标文件、可执行文件、库文件 (头文件)等。文件通常是驻留在外部介质(如磁…

文件操作(C语言)

目录 一、前言 二、文件的打开和关闭 三、文件的读写 1.文件的顺序读写 2.文件的随机读写 四、文件结束的判定 一、前言 当我们向写好的通讯录程序中输入信息时&#xff0c;有时我们希望能保存输入的信息&#xff0c;不用每次打开这个程序都要重新输入&#xff0c;这时就…

文件操作详解(超级详细)

正常我们的程序在执行的时候程序结束后&#xff0c;会将所有数据清楚&#xff0c;那么我们应该如何保存数据呢&#xff1f;这里我们就需要用文件操作。 一、文件的打开和关闭 1.文件打开、关闭函数—fopen、fclose //打开文件 FILE * pf fopen ( const char * filename, const…

虚拟机安装黑苹果【虚拟机安装,黑苹果安装,黑苹果无法全屏问题】(这应该全网最全的资源了吧~)

一&#xff0c;资源下载 链接&#xff1a;https://pan.baidu.com/s/1cyGiDvkJinx8dnB57gO7UQ 提取码&#xff1a;i615 PS&#xff1a;里面有虚拟机资源&#xff0c;Drawin.ios文件和苹果镜像文件 这里只讲如何用虚拟机安装黑苹果&#xff0c;不讲如何安装虚拟机&#xff0c;下…

VMware虚拟机安装黑苹果10.15 || AMD R7 5800处理器

VMwar版本&#xff1a;16Pro 链接&#xff1a;https://pan.baidu.com/s/1qGHEynWSV4YS9WSNonxiuA?pwdazvh 提取码&#xff1a;azvh macOS链接&#xff0c;版本为Catalina 10.5。这个版本后&#xff0c;os安装包就过10G了&#xff0c;会特别卡。 链接&#xff1a;https://pan…

VMware16安装macOS10.15.1 - 黑苹果 - osx虚拟机

效果图 步骤 下载安装VMware&#xff0c;并且利用unlocker开启macos的支持VMware利用unlocker开启MacOS支持_Rudon滨海渔村的博客-CSDN博客效果步骤下载安装vmware16http://www.winwin7.com/soft/17946.html下载unlocker3.0 &#xff08;这里包括了darwin.iso和darwinPre15.is…

vm虚拟机15.5安装黑苹果maxos-10.14

鼎峰_小配针对vm虚拟机安装黑苹果maxos在学习和研究探索的过程中的一点点心得&#xff0c;从刚接触时的一脸懵逼&#xff0c;到后来慢慢的了解了&#xff0c;废话不多说&#xff0c;直接上干货。 一、需要准备的软件&#xff1a; a)解锁虚拟机MAC补丁&#xff1a;Unlocker 3.0…

图文详解如何在VMware Workstation11虚拟机上安装黑苹果Mac OS X 10.10系统

想要体验黑苹果系统当然要借助于VMware虚拟机了&#xff0c;那么下面大家就来看看亦是美网络小编的图文详解如何在VMware Workstation11虚拟机上安装黑苹果Mac OS X 10.10系统的教程吧&#xff01; 小编的安装环境&#xff1a; 实体机windows8.1专业版 VMware workstation 1…

win10上的VMware安装黑Mac(黑苹果、AMD)

使用AMD处理器的笔记本&#xff0c;在虚拟机上安装MAC操作系统。 本机安装配置&#xff1a; 华硕天选 AMD Ryzen 4800H 24G运存 Mac OS 10.13 High Sierra 1. 下载所需资源 所需资源下载链接&#xff1a; mac os 10.13镜像&#xff0c;其他工具 链接: https://pan.baidu.com/s/…

VMware虚拟机安装macOS黑苹果教程,亲测流程,全过程问题解决方案记录

先介绍流程,安装过程中遇到的问题都在最后列出并写出解决方案,找解决方案的直接到最后 准备: 1.VMware虚拟机 我的比较老,为VMware Workstation 14 Pro 14.1.3 build-9474260 2.unlocker 解锁VM的macOS系统 3.macOS的小白版cdr安装包(推荐)或者macOS的dmg安装包 4.如果…

Windows下VMmare黑苹果macOS Catalina 10.15虚拟机安装VMware tools工具

请先安装好macOS Catalina 10.15虚拟机。 VMware 10.15.5安装macOS Catalina 10.15请参考我的博客 Windows下VMware Workstations Pro15.5.0安装macOS Catalina 10.15虚拟机&#xff08;详细教程&#xff09; 如果VMware安装的虚拟机不安装VMware tools工具将无法全屏、进行虚…

Windows 10虚拟机Vmware 安装 黑苹果macos10.14

工具链接 提取码&#xff1a;zko1 VMware16.2.3安装 VMware16.2.3 连接手机有问题&#xff0c;改用 VMware15.5.6-16341506 流程: 虚拟机 MacOS系统解锁创建虚拟机安装macOS安装VMware tools 虚拟机 MacOS系统解锁 使用工具&#xff1a;Unlocker.7z 停止VM服务:停止所有VMwa…

黑苹果从入门到精通:最详细的VMware安装macOS教程

前言 不知为何&#xff0c;以前我发的两篇关于黑苹果的文章或没过审或被删除&#xff0c;最近SMZDM上有不少优质的黑苹果文章发出来&#xff0c;貌似禁令已开&#xff0c;前段时间在一篇写的很不错的黑果文章下吹牛说今年要写一个系列&#xff0c;故有了这篇文章作为系列的开头…

VMware虚拟机安装黑苹果MacOS Mojave系统详细教程

更多资源请百度搜索&#xff1a;前端资源网 欢迎关注我的博客&#xff1a;www.w3h5.com 大家好&#xff0c;我的主要更新渠道是自己搭建的博客&#xff0c;为了节省流量&#xff0c;我开了防盗链。。。所以其他平台可能会有图片不能显示的问题&#xff0c;请转至我的博客进行查…

给windows装个Mac黑苹果虚拟机

点击上方↑↑↑蓝字[协议分析与还原]关注我们 “ windows下安装使用苹果Mac虚拟机。” 平常的生活工作中&#xff0c;我大部分时候使用Windows&#xff0c;偶尔用用Mac。实在是用不惯Mac&#xff0c;但有的时候&#xff0c;有些工作还是需要在Mac上搞&#xff0c;不得不用&…

分享Win10虚拟机VMware安装黑苹果MacOS Sierra图文教程

虚拟机VMware安装黑苹果MacOS详细图文教程&#xff0c;安装也比较简单亿破姐这里使用的但是过程挺复杂了。 准备工作 &#xff08;1&#xff09;虚拟机 VMware Workstation Pro &#xff08;2&#xff09;解锁虚拟机MAC补丁 Unlocker &#xff08;3&#xff09;苹果系统懒人…

使用VmWare安装黑苹果系统

目录 1.介绍2.破解安装VMware3.unlocker解锁虚拟机3.1 关闭VMware相关的进程3.2 执行安装命令 4.VmWare创建虚拟机5. 下载并配置镜像以及虚拟机设置5.1 修改镜像5.2 修改虚拟机安装路径文件内容 6. 选择镜像启动虚拟机7.安装macOS系统7.1 开启此虚拟机7.2 选择语言->简体中文…