- 看过一遍视频,有了点思路之后写的
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
void read_file(char *file);//函数声明
void poll(char *file);
void sys_err(const char *buf)
{
perror(buf);
exit(0);
}
void poll(char *file) //判断文件是否为目录文件,并且输出文件大小
{
struct stat st;
if(stat(file, &st) < 0) //获取文件inode信息
sys_err("stat");
if((st.st_mode & S_IFMT) == S_IFDIR) //判断输入的文件名是目录还是其他类型的文件,如果是目录开始遍历目录
read_file(file);//遍历目录的记录项
//else
printf("%8d\t%s\n", (int)st.st_size, file);//输出文件大小
return ;
}
void read_file(char *file) //遍历目录的记录项
{
DIR *dir;
struct dirent *read;
char buff[255] = "0";
if((dir = opendir(file)) < 0)//获取文件的DIR指针
sys_err("opendir");
//当read==NULL的时候,说明该条目录已经遍历完毕
while((read = readdir(dir)) != NULL) {
if(strcmp(read->d_name,".") == 0 || strcmp(read->d_name, "..") == 0) //.和.. 一个指向当前目录,一个指向上一级目录,为了避免死循环,当记录项是.和..的时候跳过,继续读下一条记录项
continue;
else {
sprintf(buff, "%s/%s", file, read->d_name); //通过人为的加上'/',使得poll函数可以访问下一级目录
poll(buff);//判断本条记录项是目录还是文件
}
}
closedir(dir);
return;
}
int main(int argc, char *argv[])
{
if(argc < 2) {
printf("./a.out path\n");
exit(0);
}
poll(argv[1]);
return 0;
}
- 注意事项:
在设计函数接口的时候,要注意char型指针的级别,在poll函数的需要接收一个文件名,这肯定是一个char型的指针,因为char *argv[]本质上是一个2级指针,所以只要把argv[1]这个1级指针传过去就好
因为接口都是用来传递字符串的,所以设置成char*类型就可以了
(st.st_mode & S_IFMT) == S_IFDIR)
这条语句在“文件I/O函数练习及注意事项”博文里已经写到,这里就不在赘述sprintf(buff, "%s/%s", file, read->d_name)
这句话很重要,在添加’/’的时候一定要传给第三个字符串,不要传给file,如果给了file,在运行完本次的poll,在调用下一条记录项的时候,file里面的内容仍继续参与寻址,但此时file里面还存有上一条记录项的文件名;简单的一句换归纳,就是file无法被除第一条记录项之外的其他记录项用作寻址功能。(如果您看到本条,并有更好的说法欢迎指正)- 在linux里面,a/b和a//b同样适用,都可以寻找到文件而且中间的’/’的个数可以不为1,最大值不知道,但这个手动添加’/’提供了方便
- 由于上述代码为本人书写,所以有很多细节没有考虑到,只是实现了大体的功能,下列代码考虑到了大部分细节,以供参考
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#define MAX_PATH 1024 //设定路径最大长度,防止死循环
void dirwalk(char *dir, void(*fcn)(char *)) //遍历目录文件的记录项
{
char name[MAX_PATH];
struct dirent *dp;
DIR *dfd;
if((dfd = opendir(dir)) == NULL) { //打开dir的记录项指针
fprintf(stderr, "dirwalk: can't open %s\n", dir);
}
while((dp = readdir(dfd)) != NULL) {//读取记录项
if(strcmp(dp->d_name,".") == 0 ||strcmp(dp->d_name, "..") == 0)
continue;
if(strlen(dir) + strlen(dp->d_name) + 2 > sizeof(name))如果,目录项和文件项的和再加上预留出来的'/'长度以及字符串末尾的'\0'大于name的长度,字符串就溢出了,就不能执行fcn函数了
fprintf(stderr, "dirwalk: name %s %s too long\n", dir, dp->d_name);
else {
sprintf(name, "%s/%s", dir, dp->d_name);//人为加上地址符号
(*fcn)(name);//读取文件大小并输出
}
}
closedir(dfd);
}
void fsize(char *name)//读取文件大小并输出
{
struct stat stbuf;
if(stat(name, &stbuf) == -1) {
fprintf(stderr, "fsize: can't access %s\n", name);
return;
}
if((stbuf.st_mode & S_IFMT) == S_IFDIR) //判断是否是目录
dirwalk(name, fsize);
printf("%8ld %s\n", stbuf.st_size, name);//读取文件大小
}
int main(int argc, char **argv)
{
if(argc == 1) //如果没有接收到字符,就默认打开当前目录
fsize(".");
else
while(--argc > 0)
fsize(*++argv); // *++argv等同于argv[1]
return 0;
}