Linux系统编程 -文件和目录操作函数
@[toc]
01. 学习目标
- 掌握dup、dup2函数的使用
- 掌握stat/lstat函数的使用
- 掌握fcntl函数的使用
- 掌握目录遍历相关的函数使用
02. 文件操作相关函数
2.1 stat函数(重点)
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int lstat(const char *pathname, struct stat *buf);
功能:
获取文件状态信息
stat和lstat的区别:
当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;
而stat返回的是该链接指向的文件的信息。
参数:
path:文件名
buf:保存文件信息的结构体
返回值:
成功: 0
失败: -1
struct stat结构体说明:
struct stat {
dev_t st_dev; //文件的设备编号
ino_t st_ino; //节点
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink; //连到该文件的硬连接数目,刚建立的文件值为1
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev; //(设备类型)若此文件为设备文件,则为其设备编号
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize; //块大小(文件系统的I/O 缓冲区大小)
blkcnt_t st_blocks; //块数
time_t st_atime; //最后一次访问时间
time_t st_mtime; //最后一次修改时间
time_t st_ctime; //最后一次改变时间(指属性)
};c
示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
int main()
{
int ret = -1;
struct stat s;
//获取指定文件信息
ret = stat("txt",&s);
if(-1 == ret)
{c
perror("stat");
return 1;
}
//文件属性信息
printf("st_dev:%lu\t",s.st_dev);
printf("st_ino:%ld\t",s.st_ino);
printf("st_nlink:%lu\n",s.st_nlink);
printf("st_uid:%d\t",s.st_uid);
printf("st_gid:%d\t",s.st_gid);
printf("st_size:%ld\n",s.st_size);;
return 0;
}
2.1.1第一个stat版本:
stat函数的st_mode文档查看:
意思就是用S_IFMT八进制的017和文件类型的八进制数异或,异或的结果对应它们的文件类型
2.1.2第二个stat版本:
文件类型判断应使用宏函数
st_mode(16位整数)参数说明
2.1.3显示文件类型代码:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
//显示文件类型版本2
void show_file_type_v2(struct stat *s)
{
//普通文件
if(S_ISREG(s->st_mode))
{
printf("IS a regular file\n");
}
//目录
if(S_ISDIR(s->st_mode))
{
printf("IS a directory\n");
}
//字符设备
if(S_ISCHR(s->st_mode))
{
printf("IS a character device\n");
}
//块设备
if(S_ISBLK(s->st_mode))
{
printf("IS a block device\n");
}
//符号链接
if(S_ISLNK(s->st_mode))
{
printf("IS a sysbolic link\n");
}
//管道文件
if(S_ISFIFO(s->st_mode))
{
printf("IS a FIFO\n");
}
//套接字
if(S_ISSOCK(s->st_mode))
{
printf("IS a socket\n");
}
}
void show_file_type(struct stat *s)
{
switch(s->st_mode & S_IFMT)
{
case S_IFREG:
printf("该文件是普通文件\n");
break;
case S_IFDIR:
printf("该文件是目录\n");
break;
case S_IFCHR:
printf("该文件是字符设备\n");
break;
case S_IFBLK:
printf("该文件是块设备\n");
break;
case S_IFSOCK:
printf("该文件是套接字文件\n");
break;
case S_IFIFO:
printf("该文件是管道\n");
break;
case S_IFLNK:
printf("该文件是符号链接\n");
break;
default:
printf("其它文件\n");
break;
}
}
int main(int argc,char **argv)
{
int ret = -1;
struct stat s;
//容错判断
if(argc!=2)
{
printf("input:./a.out filename\n");
return 1;
}
ret = stat(argv[1],&s);
if(-1 == ret)
{
perror("stat");
return 1;
}
//显示文件类型
show_file_type(&s);
show_file_type_v2(&s);
return 0;
}
2.1.4显示文件权限代码
//判断文件所属者权限
if (s.st_mode & S_IRUSR)
printf("r");
else
printf("-");
s.st_mode & S_IWUSR ? printf("w") : printf("-");
s.st_mode & S_IXUSR ? printf("x") : printf("-");
//判断文件所属组权限
s.st_mode & S_IRGRP ? printf("r") : printf("-");
s.st_mode & S_IWGRP ? printf("w") : printf("-");
s.st_mode & S_IXGRP ? printf("x") : printf("-");
//判断文件其它权限
s.st_mode & S_IROTH ? printf("r") : printf("-");
s.st_mode & S_IWOTH ? printf("w") : printf("-");
s.st_mode & S_IXOTH ? printf("x") : printf("-");
printf("\n");
2.2 access函数
#include <unistd.h>
int access(const char *pathname, int mode);
功能:测试指定文件是否具有某种属性
参数:
pathname:文件名
mode:文件权限,4种权限
R_OK: 是否有读权限
W_OK: 是否有写权限
X_OK: 是否有执行权限
F_OK: 测试文件是否存在
返回值:
0: 有某种权限,或者文件存在
-1:没有,或文件不存在
access("txt", F_OK);
2.3 chmod函数
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
功能:修改文件权限
参数:
filename:文件名
mode:权限(8进制数)
返回值:
成功:0
失败:-1
2.4 chown函数
#include <unistd.h>
int chown(const char *pathname, uid_t owner, gid_t group);
功能:修改文件所有者和所属组
参数:
pathname:文件或目录名
owner:文件所有者id,通过查看 /etc/passwd 得到所有者id
group:文件所属组id,通过查看 /etc/group 得到用户组id
返回值:
成功:0
失败:-1
2.5 truncate函数
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
功能:修改文件大小
参数:
path:文件文件名字
length:指定的文件大小
a)比原来小, 删掉后边的部分
b)比原来大, 向后拓展
返回值:
成功:0
失败:-1
2.6 link函数
#include <unistd.h>
int link(const char *oldpath, const char *newpath);
功能:创建一个硬链接
参数:
oldpath:源文件名字
newpath:硬链接名字
返回值:
成功:0
失败:-1
2.7 symlink函数
#include <unistd.h>
int symlink(const char *target, const char *linkpath);
功能:创建一个软链接
参数:
target:源文件名字
linkpath:软链接名字
返回值:
成功:0
失败:-1
2.8 readlink函数
#include <unistd.h>
ssize_t readlink(const char *pathname, char *buf, size_t bufsiz);
功能:读软连接对应的文件名,不是读内容(该函数只能读软链接文件)
参数:
pathname:软连接名c
buf:存放软件对应的文件名
bufsiz :缓冲区大小(第二个参数存放的最大字节数)
返回值:
成功:>0,读到buf中的字符个数
失败:-1
2.9 unlink函数
#include <unistd.h>
int unlink(const char *pathname);
功能:删除一个文件(软硬链接文件)
参数:
pathname:删除的文件名字
返回值:
成功:0
失败:-1
2.10 rename函数
#include <stdio.h>
int rename(const char *oldpath, const char *newpath);
功能:把oldpath的文件名改为newpath
参数:
oldpath:旧文件名
newpath:新文件名
返回值:
成功:0
失败:-1
03. 文件描述符复制(重点)
3.1 概述
==dup() 和 dup2()== 是两个非常有用的系统调用,都是用来复制一个文件的描述符,使新的文件描述符也标识旧的文件描述符所标识的文件。
这个过程类似于现实生活中的配钥匙,钥匙相当于文件描述符,锁相当于文件,本来一个钥匙开一把锁,相当于,一个文件描述符对应一个文件,现在,我们去配钥匙,通过旧的钥匙复制了一把新的钥匙,这样的话,旧的钥匙和新的钥匙都能开启这把锁。
对比于 dup(), dup2() 也一样,通过原来的文件描述符复制出一个新的文件描述符,这样的话,原来的文件描述符和新的文件描述符都指向同一个文件,我们操作这两个文件描述符的任何一个,都能操作它所对应的文件。
fd3复制fd1,它们有着相同文件属性,而且不会被覆盖掉;因为只要有其中一个fd标志改动,其它标志都知道,之间有偏移量。文件表后面是公共的;
3.1 dup函数
#include <unistd.h>
int dup(int oldfd);
功能:
通过 oldfd 复制出一个新的文件描述符,新的文件描述符是调用进程文件描述符表中最小可用的文件描述符,最终 oldfd 和新的文件描述符都指向同一个文件。
参数:
oldfd : 需要复制的文件描述符 oldfd
返回值:
成功:新文件描述符
失败: -1
示例代码:
int main()
{
int fd = -1;
int newfd = -1;
//1.打开文件
fd = open("txt",O_RDWR |O_CREAT ,0644);
if(-1 == fd)
{
perror("open");
return 1;
}
//复制文件描述符
newfd=dup(fd);
if(newfd == -1)
{
perror("dup");
return 1;
}
printf("fd: %d newfd:%d\n",fd,newfd);
write(fd,"ABCDEFG",7);
write(newfd,"1234567",7);
//3.关闭文件
close(fd);
close(newfd);
return 0;
}
3.2 dup2函数
应用场景一般在重定向
#include <unistd.h>
int dup2(int oldfd, int newfd);
功能:
通过 oldfd 复制出一个新的文件描述符 newfd,如果成功,newfd 和函数返回值是同一个返回值,最终 oldfd 和新的文件描述符 newfd 都指向同一个文件。
参数:
oldfd : 需要复制的文件描述符
newfd : 新的文件描述符,这个描述符可以人为指定一个合法数字(0 - 1023),如果指定的数字已经被占用(和某个文件有关联),此函数会自动关闭 close() 断开这个数字和某个文件的关联,再来使用这个合法数字。
返回值:
成功:返回 newfd
失败:返回 -1
//复制文件描述符
//newfd=dup(fd);
newfd = 2;
//如果文件描述符2已经跟某个文件关联了,那就会先解除,然后与fd关联同一个文件
newfd=dup2(fd,newfd);
3.3 示例分析
04. fcntl函数
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */);
功能:改变已打开的文件性质,fcntl针对描述符提供控制。
参数:
fd:操作的文件描述符
cmd:操作方式
arg:针对cmd的值,fcntl能够接受第三个参数int arg。
返回值:
成功:返回某个其他值
失败:-1
fcntl函数有5种功能:
复制一个现有的描述符(cmd=F_DUPFD)
获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD)
获得/设置文件状态标记(cmd=F_GETFL或F_SETFL)
获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN)
获得/设置记录锁(cmd=F_GETLK, F_SETLK或F_SETLKW)
1)复制一个现有的描述符:
int fd = -1;
int newfd = -1;
int ret = -1;
//1.读文件
fd=open("txt",O_WRONLY | O_CREAT , 0644);
if(-1 == fd)
{
perror("open");
return 1;
}
printf("fd = %d\n",fd);
//2.文件描述符复制
//功能等价于dup函数
//第三个参数0表示返回一个最小的可用的文件描述符,并且大于获等于0
newfd=fcntl(fd,F_DUPFD,0);
if(-1 == newfd)
{
perror("fcntl");
return 0;
}
printf("newfd: %d\n",newfd);
//3.写操作
write(fd,"123456789",9);
write(newfd,"abcdefg",7);
2)获得/设置文件状态标记
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
//文件描述符复制
int main(void)
{
int fd = -1;
int ret = -1;
//1. 打开文件 Ctrl + P
fd = open("txt", O_RDWR | O_CREAT | O_TRUNC, 0644);
if (-1 == fd)
{
perror("open");
return 1;
}
printf("fd: %d\n",fd);
//2. 获取文件状态标志
ret = fcntl(fd, F_GETFL);
if (-1 == ret)
{
perror("fcntl");
return 1;
}
if (ret & O_NONBLOCK)
{
printf("设置为非阻塞...\n");
}
else
{
printf("设置为阻塞...\n");
}
//设置为非阻塞
ret |= O_NONBLOCK;
ret = fcntl(fd, F_SETFL, ret);
if (-1 == ret)
{
perror("fcntl");
return 1;
}
//2. 获取文件状态标志
ret = fcntl(fd, F_GETFL);
if (-1 == ret)
{
perror("fcntl");
return 1;
}
if (ret & O_NONBLOCK)
{
printf("设置为非阻塞...\n");
}
else
{
printf("设置为阻塞...\n");
}
//3. 关闭文件
close(fd);
return 0;
}
3)1-2-3组合示例:
// 等价于dup()
int new_fd = fcntl(fd, F_DUPFD, 0);
// 获取文件状态标志
int flag = fcntl(fd, F_GETFL, 0);
switch (flag & O_ACCMODE)
{
case O_RDONLY:
printf("read only\n");
break;
case O_WRONLY:
printf("write only\n");
break;
case O_RDWR:
printf("read and write\n");
break;
default:
break;
}
if (flag & O_APPEND)
{
printf("append\n");
}
flag |= O_APPEND; // 追加flag
fcntl(fd, F_SETFL, flag); //设置文件状态标记
05. 目录相关操作(掌握)
5.1 getcwd函数
#include <unistd.h>
char *getcwd(char *buf, size_t size);
功能:获取当前进程的工作目录
参数:
buf : 缓冲区,存储当前的工作目录
size : 缓冲区大小
返回值:
成功:buf中保存当前进程工作目录位置
失败:NULL
5.2 chdir函数
#include <unistd.h>
int chdir(const char *path);
功能:修改当前进程(应用程序)的路径
参数:
path:切换的路径
返回值:
成功:0
失败:-1
代码:
int ret = -1;
char buf[SIZE]={0};
//getcwd chdir
//1.获取当前工作路径
memset(buf,0,SIZE);
if(NULL == getcwd(buf,SIZE))
{
perror("getcwd");
return 0;
}
printf("buf:%s\n",buf);
//2.修改当前路径
ret = chdir("/home/test/");
if(-1 == ret)
{
perror("chdir");
return 0;
}
//3.获取当前工作路径
memset(buf,0,SIZE);
if(NULL == getcwd(buf,SIZE))
{
perror("getcwd");
return 0;
}
printf("buf:%s\n",buf);
5.3 opendir函数
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
功能:打开一个目录
参数:
name:目录名
返回值:
成功:返回指向该目录结构体指针
失败:NULL
5.4 closedir函数
#include <sys/types.h>
#include <dirent.h>
int closedir(DIR *dirp);
功能:关闭目录
参数:
dirp:opendir返回的指针
返回值:
成功:0
失败:-1
DIR * dir = NULL;
//1.打开一个目录
dir = opendir("test");
if(NULL == dir)
{
perror("opendir");
return 0;
}
printf("打开成功!\n");
//2.关闭目录
ret = closedir(dir);
if(NULL == dir)
{
perror("closedir");
return 1;
}
printf("关闭成功!\n");
我们也可以自己写一个mkdir函数:
5.5 readdir函数
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
功能:读取目录
参数:
dirp:opendir的返回值
返回值:
成功:目录结构体指针
失败:NULL
相关结构体说明:
struct dirent
{
ino_t d_ino; // 此目录进入点的inode
off_t d_off; // 目录文件开头至此目录进入点的位移
signed short int d_reclen; // d_name 的长度, 不包含NULL 字符
unsigned char d_type; // d_type 所指的文件类型
char d_name[256]; // 文件名
};
d_type文件类型说明:
取值 | 含义 |
---|---|
DT_BLK | 块设备 |
DT_CHR | 字符设备 |
DT_DIR | 目录 |
DT_LNK | 软链接 |
DT_FIFO | 管道 |
DT_REG | 普通文件 |
DT_SOCK | 套接字 |
DT_UNKNOWN | 未知 |
示例:
DIR *open_d = NULL;
struct dirent *dir = NULL;
//1.打开目录
open_d = opendir("test1");
if( open_d == NULL)
{
perror("opendir");
return 1;
}
printf("读取目录成功\n");
//2.读取目录属性
while(1)
{
dir = readdir(open_d);
if(dir == NULL)
{
perror("readdir");
break;
}
// unsigned char的缩写hu
printf("d_type: %hu \t d_name: %s\n",dir->d_type,dir->d_name);
}
closedir(open_d);
06. 时间相关函数
utime
time
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);
struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);
time_t mktime(struct tm *tm);
07.作业
1) 实现文件拷贝,保留文件属性
2)实现ls -l的功能
提示:
// 文件所有者 #include <pwd.h>
char* fileUser = getpwuid(st.st_uid)->pw_name;
// 文件所属组 #include <grp.h>
char* fileGrp = getgrgid(st.st_gid)->gr_name;
// 修改时间 #include <time.h>
char* time = ctime(&st.st_mtime);
char mtime[512] = { 0 };
strncpy(mtime, time, strlen(time) - 1);
3) 实现rm功能,即可删除文件,也可删除文件夹
unlink() 删除文件,如果是链接,就删除链接,如果不是链接就删除文件。
rmdir() 只能删除空目录
4)读取指定目录中普通文件个数
08.答案
- 实现文件拷贝,保留文件属性
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
#include <utime.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
int fd1, fd2;
int len;
char buf[1024 * 4];
if(argc != 3)
{
printf("use err: mycp src_file dst_file\n");
return -1;
}
if(0 == strcmp(argv[1], argv[2]))
{
printf("源文件和目的文件不允许同名!");
return -2;
}
fd1 = open(argv[1], O_RDONLY); //只读方式打开源文件
if(-1 == fd1)
{
perror("open src err");
return -3;
}
fd2 = open(argv[2], O_WRONLY | O_CREAT, 0666); //只写方式打开目的文件
if(-1 == fd2)
{
close(fd1); //关闭文件1
perror("open dst err");
return -3;
}
while(1)
{
len = read(fd1, buf, sizeof(buf)); //从源文件读取内容,返回值为读取大小
if(len <= 0)
{
break; //跳出循环
}
//把读取的内容,写入另外一个文件,读多少写多少
write(fd2, buf, len);
}
close(fd1); //关闭文件
close(fd2);
//获取源文件属性
struct stat src_stat;
stat(argv[1], &src_stat);
//修改目标文件时间
struct utimbuf timbuf;
timbuf.actime = src_stat.st_atime; //访问时间
timbuf.modtime = src_stat.st_mtime; //修改时间
utime(argv[2], &timbuf);
//修改权限
chmod(argv[2], src_stat.st_mode);
// 修改所有者
int ret = chown(argv[2], src_stat.st_uid, src_stat.st_gid);
if(ret < 0)
{
perror("chown");
}
return 0;
}
2)实现ls -l的功能
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("./a.out filename\n");
return -1;
}
struct stat st;
int ret = stat(argv[1], &st);
if(ret == -1)
{
perror("stat");
return -2;
}
// 存储文件类型和访问权限
char perms[11] = {0};
// 判断文件类型
switch(st.st_mode & S_IFMT)
{
case S_IFLNK:
perms[0] = 'l';
break;
case S_IFDIR:
perms[0] = 'd';
break;
case S_IFREG:
perms[0] = '-';
break;
case S_IFBLK:
perms[0] = 'b';
break;
case S_IFCHR:
perms[0] = 'c';
break;
case S_IFSOCK:
perms[0] = 's';
break;
case S_IFIFO:
perms[0] = 'p';
break;
default:
perms[0] = '?';
break;
}
// 判断文件的访问权限
// 文件所有者
perms[1] = (st.st_mode & S_IRUSR) ? 'r' : '-';
perms[2] = (st.st_mode & S_IWUSR) ? 'w' : '-';
perms[3] = (st.st_mode & S_IXUSR) ? 'x' : '-';
// 文件所属组
perms[4] = (st.st_mode & S_IRGRP) ? 'r' : '-';
perms[5] = (st.st_mode & S_IWGRP) ? 'w' : '-';
perms[6] = (st.st_mode & S_IXGRP) ? 'x' : '-';
// 其他人
perms[7] = (st.st_mode & S_IROTH) ? 'r' : '-';
perms[8] = (st.st_mode & S_IWOTH) ? 'w' : '-';
perms[9] = (st.st_mode & S_IXOTH) ? 'x' : '-';
// 硬链接计数
int linkNum = st.st_nlink;
// 文件所有者
char* fileUser = getpwuid(st.st_uid)->pw_name;
// 文件所属组
char* fileGrp = getgrgid(st.st_gid)->gr_name;
// 文件大小
int fileSize = (int)st.st_size;
// 修改时间
char* time = ctime(&st.st_mtime);
char mtime[512] = {0};
strncpy(mtime, time, strlen(time)-1);
char buf[1024];
sprintf(buf, "%s %d %s %s %d %s %s", perms, linkNum, fileUser, fileGrp, fileSize, mtime, argv[1]);
printf("%s\n", buf);
return 0;
}
- 实现rm功能,即可删除文件,也可删除文件夹
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int rm(const char* path)
{
struct stat stat_buf;
int ret = stat(path, &stat_buf); //获取文件属性
if(ret < 0)
{
perror("stat");
return -1;
}
// 判断path是个文件还是目录
// 如果是文件,直接unlink然后返回
if(!S_ISDIR(stat_buf.st_mode))
{
unlink(path);
return 0;
}
char buf[1024];
DIR* dir = opendir(path); //打开目录
if(dir == NULL)
{
perror("opendir");
return -1;
}
struct dirent* entry = NULL;
// 如果path是目录,遍历目录中的所有目录项
while( (entry = readdir(dir)) != NULL )
{
sprintf(buf, "%s/%s", path, entry->d_name); //必须先放前面
if(entry->d_type == DT_REG || entry->d_type == DT_LNK)
{//如果是普通文件,或链接文件,则删除
unlink(buf);
}
if(entry->d_type == DT_DIR)
{//如果是目录
// 忽略.和..目录
if(strcmp(entry->d_name, ".") == 0 ||strcmp( entry->d_name, "..") == 0)
{
continue;
}
rm(buf); //递归删除
}
}
closedir(dir);
rmdir(path); //删除目录
return 0;
}
int main(int argc, char* argv[])
{
if(argc == 1)
{
printf("usage: %s [pathname]\n", argv[0]);
return 0;
}
rm(argv[1]);
return 0;
}
4.读取指定目录中普通文件个数
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <sys/types.h>
int get_file_num(char* root)
{
int total = 0;
DIR* dir = NULL;
// 打开目录
dir = opendir(root);
// 循环从目录中读文件
char path[1024];
// 定义记录xiang指针
struct dirent* ptr = NULL;
while( (ptr = readdir(dir)) != NULL)
{
// 跳过. he ..
if(strcmp(ptr->d_name, ".") == 0 || strcmp(ptr->d_name, "..") == 0)
{
continue;
}
// 判断是不是目录
if(ptr->d_type == DT_DIR)
{
///home/deng/share
sprintf(path, "%s/%s", root, ptr->d_name);
// 递归读目录
total += get_file_num(path);
}
// 如果是普通文件
if(ptr->d_type == DT_REG)
{
total ++;
}
}
closedir(dir);
return total;
}
int main(int argc, char* argv[])
{
if(argc < 2)
{
printf("./a.out path");
exit(1);
}
int total = get_file_num(argv[1]);
printf("%s has regfile number: %d\n", argv[1], total);
return 0;
}
- 点赞
- 收藏
- 关注作者
评论(0)