1、判断文件是否是目录文件
任务描述:
- 给出一个文件的绝对路径,判断该文件是否是目录文件
- 将文件的绝对路径做输入参数,打印信息表明该文件是否为目录
相关知识:
-
S_ISDIR (st_mode) :判断是否为目录
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> struct stat buf; int main(int argc ,char *argv[]) { if(argc!=2){ perror("argc error\n"); exit(1); } if(stat(argv[1],&buf)!=0){ perror("stat error\n"); exit(1); } if(S_ISDIR(buf.st_mode)) printf("it id a dir\n"); else printf("it isn't a dir\n"); return 0; }
2、列出指定目录下所有文件名
任务描述:
- 绝对路径名做输入参数,打印出该路径下所有文件名
相关知识:
-
DIR* opendir (const char * path )
opendir()用来打开参数name 指定的目录, 并返回DIR*形态的目录流, 和open()类似, 接下来对目录的读取和搜索都要使用此返回值。返回值:成功则返回DIR* 型态的目录流, 打开失败则返回NULL。不用管DIR的内部结构是什么样的,只要知道要传给readdir()函数的参数就行了。
-
struct dirent *readdir(DIR *dir):读取目录
它的参数是opendir函数返回的DIR*句柄,而该函数的返回值是struct dirent* 类型,这个结构体定义如下:
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* offset to the next dirent */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file */
char d_name[256]; /* filename */
};
d_name存放的是文件的名字。
Readdir返回指向下一个目录项的指针。
main.c:
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> struct dirent *entry; int main(int argc ,char *argv[]) { char path[1024]; DIR *dirptr=NULL; if(argc!=2){ perror("argc error\n"); exit(1); } if((dirptr=opendir(argv[1]))==NULL){ perror("stat error\n"); exit(1); } else{ while(entry=readdir(dirptr)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 //sprintf(path,"%s/%s",argv[1],entry->d_name);//输出绝对路径 printf("%s\n",entry->d_name); } closedir(dirptr); } return 0; }
3、列出指定目录下所有文件的绝对路径
相关知识:
-
绝对路径由指定目录的绝对路径加上文件的相对路径得到
-
int sprintf( char *buffer, const char *format, [ argument] … ):字符串格式化命令,主要功能是把格式化的数据写入某个字符串中
buffer:char型指针,指向将要写入的字符串的缓冲区。
format:格式化字符串。
[argument]...:可选参数,可以是任何类型的数据。
返回值:字符串长度(strlen)
main.c:
#include<stdio.h> #include<sys/types.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 struct dirent *entry; int main(void) { DIR *dirptr=NULL; char name[N]; char buf[N]; char path[N]; printf("please input a path\n"); fgets(name,N,stdin);//输入路径 int i=strlen(name); name[i-1]='\0';//将fgets最后的回车置零 if((dirptr=opendir(name))==NULL){ perror("your input dir is not existed\n"); exit(1); } else{ chdir(name);//切换到name这个目录 getcwd(buf,N);//获得输入的目录并把当前目录的绝对地址保存到 buf 中 while(entry=readdir(dirptr)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0)
continue;//如果输入的是相对路径,不处理 sprintf(path,"%s/%s",buf,entry->d_name);//输出绝对路径 printf("%s\n",path); } closedir(dirptr); } return 0; }
4、递归列出指定目录下的所有文件的绝对路径
任务描述:
- 输入绝对路径,输出该路径下所有文件及子目录下文件的绝对路径
相关知识:
- 递归函数
一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数)。
它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程序往往十分简洁易懂。
一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。
注意:
(1) 递归就是在过程或函数里调用自身;
(2) 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口,否则将无限进行下去(死锁)。
-
在判断文件是目录文件后,递归调用函数遍历该子目录
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 struct dirent *entry; void fun(char *pathname) { DIR *dp; char buf[N],path[N]; if((dp=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把相对路径变为绝对路径 getcwd(buf,N);//获得输入的路径并把当前路径的绝对路径保存到 buf 中 while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 sprintf(path,"%s/%s",buf,entry->d_name);//输出绝对路径 struct stat st; stat(path,&st); if(S_ISDIR(st.st_mode)) fun(path); else printf("%s\n",path); } closedir(dp); } int main(void) { char name[N]; printf("please input a path\n"); fgets(name,N,stdin);//输入路径 int i=strlen(name); name[i-1]='\0';//将fgets最后的回车置零 fun(name); return 0; }
5、递归列出当前目录下所有文件,并按文件类型进行统计其个数
相关知识:
-
我们可以通过stat获取文件的类型和文件大小等信息。文件类型有:普通文件、目录文件、块特殊文件、字符特殊文件、FIFO、套接字和符号链接。
-
遇到目录文件时,递归调用函数自身,判断子目录下的文件是否是普通文件。
-
符号链接(软链接)是一类特殊的文件, 其包含有一条以绝对路径或者相对路径的形式指向其它文件或者目录的引用。
符号链接的操作是透明的:对符号链接文件进行读写的程序会表现得直接对目标文件进行操作。某些需要特别处理符号链接的程序(如备份程序)可能会识别并直接对其进行操作。
一个符号链接文件仅包含有一个文本字符串,其被操作系统解释为一条指向另一个文件或者目录的路径。它是一个独立文件,其存在并不依赖于目标文件。如果删除一个符号链接,它指向的目标文件不受影响。如果目标文件被移动、重命名或者删除,任何指向它的符号链接仍然存在,但是它们将会指向一个不复存在的文件。这种情况被有时被称为被遗弃。
- S_ISREG (st_mode) 是否为普通文件
-
S_ISLNK (st_mode) 判断是否为符号连接
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 struct dirent *entry; int a=0,b=0,c=0,d=0,e=0,f=0; void fun(char *pathname) { DIR *dp; char buf[N],path[N];int i; if((dp=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把当前目录的绝对地址保存到 buf 中 getcwd(buf,N);//获得输入的目录并把当前目录的绝对地址保存到 buf 中 while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 sprintf(path,"%s/%s",buf,entry->d_name);//输出绝对路径 printf("path file is %s\n",path); struct stat st; stat(path,&st); if(S_ISDIR(st.st_mode)) fun(path); else if(S_ISLNK(st.st_mode)) a++; if(S_ISREG(st.st_mode)) b++; if(S_ISDIR(st.st_mode)) c++; if(S_ISCHR(st.st_mode)) d++; if(S_ISBLK(st.st_mode)) e++; if(S_ISSOCK(st.st_mode)) f++; } closedir(dp); } int main(void) { char name[N]; printf("please input a path\n"); fgets(name,N,stdin);//输入路径 int i=strlen(name); name[i-1]='\0';//将fgets最后的回车置零 fun(name); printf("符号链接=%d\n",a); printf("一般文件=%d\n",b); printf("目录=%d\n",c); printf("字符装置文件=%d\n",d); printf("块设备文件=%d\n",e); printf("socket=%d\n",f); return 0; }
6、搜索指定目录下是否存在某个文件
任务描述:
- 递归搜索指定目录下是否存在某个文件,如果存在,则输出该文件的绝对路径,不存在,则输出提示
- 指定目录路径与待搜索文件名作为输入参数,打印输出搜索结果信息
- 如果判断文件是目录文件,则需要递归进行搜索
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 int flag=0; void fun(char *pathname,char *filename) { DIR *dp; struct dirent *entry; char buf[N],path[N]; if((dp=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把当前目录的绝对地址保存到 buf 中 getcwd(buf,N);//获得输入的目录并把当前目录的绝对地址保存到 buf 中 while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 sprintf(path,"%s/%s",buf,entry->d_name);//输出绝对路径 struct stat st; if(stat(path,&st)){ printf("stat error\n"); exit(1); } if(S_ISDIR(st.st_mode)) fun(path,filename); else{ if(strcmp(entry->d_name,filename)==0){ printf("%s\n",path); ++flag; } } } //if(flag==0) //printf("flag%d\n",flag); closedir(dp); } int main(void) { char dir[N],name[N]; printf("please input a pathname\n"); fgets(dir,N,stdin);//输入路径 printf("please input a filename\n"); fgets(name,N,stdin);//输入文件名 int a=strlen(dir); dir[a-1]='\0';//将fgets最后的回车置零 int b=strlen(name); name[b-1]='\0';//将fgets最后的回车置零 fun(dir,name); if(flag==0) printf("file is not exist\n"); return 0; }
7、列出指定目录在过去一小时内被修改的文件
任务描述:
- 输出指定目录下所有当前时刻起前一个小时内被修改的文件名及其对应的最后被修改时间
相关知识:
-
在Linux下,一个文件也有三种时间,分别是:访问时间、修改时间、状态改动时间。
访问时间: 读一次这个文件的内容,这个时间就会更新。比如对这个文件运用 more、cat等命令。ls、stat命令都不会修改文件的访问时间。
修改时间: 修改时间是文件内容最后一次被修改时间。比如:vi后保存文件。ls -l列出的时间就是这个时间。
状态改动时间: 是该文件的i节点最后一次被修改的时间,通过chmod、chown命令修改一次文件属性,这个时间就会更新。 - time_t time(time_t *t):获得当前时间
返回从公元1970年1月1日的UTC时间从0时0分0秒算起到现在所经过的秒数。如果t并非空指针的话,此函数也会将返回值存到t指针所指的内存,成功返回秒数
- 通过stat结构体中的成员变量st_mtime可以获得文件的最后被修改时间
main.c:
#include<stdio.h> #include<stdlib.h> #include<sys/stat.h> #include<time.h> #include<dirent.h>
struct dirent *entry; struct stat st; int main(int argc,char *argv[]) { DIR *dp=NULL; if(argc!=2){ perror("argc error\n"); exit(1); } if((dp=opendir(argv[1]))==NULL){ perror("opendir error\n"); exit(1); } chdir(argv[1]); while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue; if(stat(entry->d_name,&st)!=0){ perror("stat error\n"); exit(1); } if(time(NULL)-st.st_mtime<3600) printf("file is :%s\nthe last modify time is:%s\n",entry->d_name,ctime(&st.st_mtime)); } closedir(dp); return 0; }
8、列出指定目录下所有可被其他用户执行的文件
相关知识:
-
使用st_mode & S_IXOTH 可以获得文件的其他用户是否可执行的权限位,如果该位为1,则该文件可以被其他用户执行,否则不能被执行。
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> struct stat st; struct dirent *entry; int main(int argc ,char *argv[]) { char buf[1000]; DIR *dirptr=NULL; if(argc!=2){ perror("argc error\n"); exit(1); } if((dirptr=opendir(argv[1]))==NULL){ perror("stat error\n"); exit(1); } else while(entry=readdir(dirptr)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 sprintf(buf,"%s/%s",argv[1],entry->d_name);//把传入的路径变为相对路径放入buf中 if(stat(buf,&st)!=0){ perror("stat error\n"); exit(1); } if(st.st_mode&S_IXOTH) printf("%s can chmod \n",entry->d_name); // else // printf("error\n"); } closedir(dirptr); return 0; }
9、列出指定目录下属于给定用户的所有文件
相关知识:
-
struct passwd * getpwnam(const char * name):从密码文件中取得指定账号的数据
getpwnam()用来逐一搜索参数name 指定的账号名称,找到时便将该用户的数据以passwd结构返回。如果返回NULL 则表示已无数据,或有错误发生。
passwd结构体定义如下:
struct passwd {
char * pw_name; /* Username. */
char * pw_passwd; /* Password. */
__uid_t -pw_uid; /* User ID. */
__gid_t -pw_gid; /* Group ID. */
char * pw_gecos; /* Real name. */
char * pw_dir; /* Home directory. -*/
char * pw_shell; /* Shell program. */
};
- 根据获取的文件所有者的用户id和通过getpwnam获得的用户id进行比较,如果相同,则可判断该文件是要搜索的给定用户的文件。
-
st_mode中的st_uid就是文件所有者的用户id。
main.c:
#include<stdio.h> #include<stdlib.h> #include<sys/stat.h> #include<pwd.h> #include<dirent.h> struct stat st; struct passwd *pw; int main(int argc,char *argv[]) { char buf[1024]; DIR *dp; struct dirent *entry; if(argc!=3){ perror("argc error\n"); exit(1); } pw=getpwnam(argv[2]); if(!pw){ perror("getpwnam error\n"); exit(1); } if((dp=opendir(argv[1]))==NULL){ perror("opendir error\n"); exit(1); } while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue; sprintf(buf,"%s/%s",argv[1],entry->d_name); if(stat(buf,&st)!=0){ perror("stat error\n"); exit(1); } if(st.st_uid==pw->pw_uid) printf("user file is :%s\n",entry->d_name); } closedir(dp); return 0; }
10、在指定目录下创建一个新目录
任务描述:
- 给出指定目录和要新建的子目录名做输入参数,打印信息表明是否创建成功
- 首先判断指定目录下是否已经存在要创建的目录,如果已存在,则不必再创建
-
通过比较指定目录下的所有目录的目录名是否与要创建的目录名称相同,来判断是否存在该目录
相关知识:
-
int mkdir(const char *pathname,mode_t mode):创建目录
参数pathname是新创建目录的目录名,mode指定该目录的访问权限,这些位将受到文件创建方式屏蔽(umask)的修正。
该函数创建一个名为pathname的空目录,此目录自动含有“.”和“..”2个登记项。这个新创建目录的用户ID被设置为调用进程的有效用户ID,其组则为父目录的组ID或者进程的有效组ID。
若调用成功,mkdir将更新该目录的st_atime、st_ctime和st_mtime,同时更新其父目录的st_ctime和st_mtime,然后返回0。若调用失败,mkdir将返回-1.
由pathname指定的新目录的父目录必须存在,并且调用进程必须具有该父目录的写权限以及pathname涉及的各个分路径目录的搜寻权限。
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 int flag=0; void fun(char *pathname,char *filename) { DIR *dp; struct dirent *entry; char buf[N]; if((dp=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把当前目录的绝对地址保存到 buf 中 getcwd(buf,N);//获得输入的目录并把当前目录的绝对地址保存到 buf 中 while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 if(strcmp(entry->d_name,filename)==0){ printf("file is exist,please try again\n"); flag++;//如果文件存在 flag++ } } closedir(dp); } int main(void) { char dir[N],name[N]; printf("please input a pathname\n"); fgets(dir,N,stdin);//输入路径 printf("please input a filename\n"); fgets(name,N,stdin);//输入文件名 int a=strlen(dir); dir[a-1]='\0';//将fgets最后的回车置零 int b=strlen(name); name[b-1]='\0';//将fgets最后的回车置零 fun(dir,name); if(flag==0)//如果文件不存在,子函数的flag没有++,仍然为0{ mkdir(name,S_IRWXU); printf("create success\n"); } return 0; }
11、在指定目录下删除一个空目录
任务描述:
- 给出指定目录和要删除的子目录名做输入参数,打印信息表明是否删除成功
- 判断要删除的目录是否存在于指定目录下,如果存在,则再判断该目录是否为空
相关知识:
-
int rmdir(const char *pathname):删除一个空目录
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 int flag=0; void fun(char *pathname,char *dirname) { DIR *dp1,*dp2;int a; struct dirent *entry; struct stat st; char buf[N]; if((dp1=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把当前目录的绝对地址保存到 buf 中 getcwd(buf,N);//获得输入的目录并把当前目录的绝对地址保存到 buf 中 while(entry=readdir(dp1)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 if(stat(entry->d_name,&st)!=0){ perror("stat error\n"); exit(1); } if(S_ISDIR(st.st_mode)){ a=strcmp(entry->d_name,dirname); if(a==0){ if((dp2=opendir(dirname))==NULL){ perror("open fail\n"); exit(1); } while(entry=readdir(dp2)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 else{ flag=-1; return ; } } flag++;//如果目录存在 flag++ closedir(dp2); } } // else printf("your input is not a dir\n"); } closedir(dp1); } int main(void) { char path[N],dir[N]; printf("please input a pathname\n"); fgets(path,N,stdin);//输入路径 printf("please input a dirname\n"); fgets(dir,N,stdin);//输入文件名 int a=strlen(path); path[a-1]='\0';//将fgets最后的回车置零 int b=strlen(dir); dir[b-1]='\0';//将fgets最后的回车置零 fun(path,dir); if(flag==-1) printf("please input a null dir\n"); else if(flag!=0)//如果目录存在,子函数flag++,不为0{ rmdir(dir); printf("remove success\n"); } else printf("dir is not exist\n"); return 0; }
12、删除指定目录下的某个普通文件
任务描述:
- 先判断指定目录下是否存在该文件,如果不存在,则返回错误。如果存在,那么调用unlink函数或remove函数来删除
- 将文件的绝对路径和文件名作输入参数,打印信息表明是否删除成功
相关知识:
-
int unlink(const char * pathname):删除文件
unlink()会删除参数pathname指定的文件。如果该文件名为最后连接点,但有其他进程打开了此文件,则在所有关于此文件的文件描述词皆关闭后才会删除。如果参数pathname为一符号连接,则此连接会被删除。
-
int remove(const char * pathname):删除文件
-
删除参数pathname指定的文件。如果参数pathname为一文件,则调用unlink()处理,若参数pathname为一目录,则调用rmdir()来处理。
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 int flag=0; void fun(char *pathname,char *filename) { DIR *dp; struct dirent *entry; char buf[N]; struct stat st; if((dp=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把当前目录的绝对地址保存到 buf 中 getcwd(buf,N);//获得输入的目录并把当前目录的绝对地址保存到 buf 中 while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0) continue;//如果输入的是相对路径,不处理 if(stat(entry->d_name,&st)!=0){ perror("stat error\n"); exit(1); } if(S_ISDIR(st.st_mode)){ if(strcmp(entry->d_name,filename)==0);{ flag++;//如果目录存在 flag++ } } if(strcmp(entry->d_name,filename)==0){ flag++;//如果文件存在 flag++ } } closedir(dp); } int main(void) { char name[N],path[N];int c; printf("please input a pathname\n"); fgets(path,N,stdin);//输入路径 printf("please input a filename\n"); fgets(name,N,stdin);//输入文件名 int a=strlen(path); path[a-1]='\0';//将fgets最后的回车置零 int b=strlen(name); name[b-1]='\0';//将fgets最后的回车置零 fun(path,name); if(flag!=0){ //如果文件存在,子函数flag++,flag不为0 c=remove(name); if(c==0) printf("remove successful\n"); else perror("please input file\n"); }else printf("no find\n"); return 0; }
13、列出指定目录下与正则表达式”abc*“匹配的所有文件
任务描述:
- 输入参数为指定目录路径和"abc*",输出所有以abc开头的文件的绝对路径
- 可在task4的基础上完成,如果是子目录,再递归调用函数访问子目录下的所有文件
相关知识:
- extern char *strstr(char *haystack,char *nedle):从字符串haystack中寻找needle第一次出现的位置,但是该函数不比较结束符NULL
- 参数haystack是一个源字符串的指针,needle为一个目的字符串的指针
main.c:
#include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<unistd.h> #include<stdlib.h> #include<dirent.h> #include<string.h> #define N 1024 void fun(char *pathname,char *filename) { DIR *dp; struct dirent *entry; char buf[N],path[N],str2[10]={0}; if((dp=opendir(pathname))==NULL){ perror("open fail\n"); exit(1); } chdir(pathname);//把相对路径变为绝对路径 getcwd(buf,N);//获得输入的路径并把当前路径的绝对路径保存到 buf 中 while(entry=readdir(dp)){ if(strcmp(entry->d_name,".")!=0&&strcmp(entry->d_name,"..")!=0){//如果输入的不是相对路径 // if(buf[strlen(buf)-1]=='/') sprintf(path,"%s/%s",buf,entry->d_name);//输出绝对路径 struct stat st;//printf("%s\n",path); if(stat(path,&st)!=0){ perror("stat error\n"); exit(1); } if(S_ISDIR(st.st_mode)) fun(path,filename); //else // { strcpy(str2,entry->d_name); if(strstr(str2,filename)) printf("%s\n",path); // } } } chdir(".."); closedir(dp); } int main(void) { char path[N],name[N]; printf("please input a path\n"); fgets(path,N,stdin);//输入路径 int a=strlen(path); path[a-1]='\0';//将fgets最后的回车置零 printf("please input a name\n"); fgets(name,N,stdin);//输入路径 int b=strlen(name); name[b-1]='\0';//将fgets最后的回车置零 fun(path,name); return 0; }