日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux目录遍历实现,列出目录下文件,可使用部分参数

發(fā)布時(shí)間:2023/12/15 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux目录遍历实现,列出目录下文件,可使用部分参数 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目標(biāo)

編程實(shí)現(xiàn)程序list.c,列表普通磁盤文件,包括文件名和文件大小。

內(nèi)容

  • 對選項(xiàng)的處理,自行編程逐個(gè)分析命令行參數(shù)。不考慮多選項(xiàng)擠在一個(gè)命令行參數(shù)內(nèi)的情況。
  • 與ls命令類似,處理對象可以有0到多個(gè)
    • 0個(gè):列出當(dāng)前目錄下所有文件
    • 普通文件:列出文件
    • 目錄:列出目錄下所有文件
  • 實(shí)現(xiàn)自定義選項(xiàng) -r, -a, -l, -h, -m 以及 –
    • -r 遞歸方式列出子目錄(每項(xiàng)要含路徑,類似find的-print輸出風(fēng)格,需要設(shè)計(jì)遞歸程序)
    • -a 列出文件名第一個(gè)字符為圓點(diǎn)的普通文件(默認(rèn)情況下不列出文件名首字符為圓點(diǎn)的文件)
    • -l 后跟一整數(shù),限定文件大小的最小值(字節(jié))
    • -h 后跟一整數(shù),限定文件大小的最大值(字節(jié))
    • -m 后跟一整數(shù)n,限定文件的最近修改時(shí)間必須在n天內(nèi)
    • – 顯式地終止命令選項(xiàng)分析

參考資料

<sys/stat.h>頭文件

文件數(shù)據(jù)結(jié)構(gòu)如下

struct stat { dev_t st_dev; // 文件所在設(shè)備ID ino_t st_ino; // 結(jié)點(diǎn)(inode)編號 mode_t st_mode; // 保護(hù)模式 nlink_t st_nlink; // 硬鏈接個(gè)數(shù) uid_t st_uid; // 所有者用戶ID gid_t st_gid; // 所有者組ID dev_t st_rdev; // 設(shè)備ID(如果是特殊文件) off_t st_size; // 總體尺寸,以字節(jié)為單位 blksize_t st_blksize; // 文件系統(tǒng) I/O 塊大小blkcnt_t st_blocks; // 已分配的 512B 塊個(gè)數(shù)time_t st_atime; // 上次訪問時(shí)間 time_t st_mtime; // 上次更新時(shí)間 time_t st_ctime; // 上次狀態(tài)更改時(shí)間 };

主要函數(shù)有

int stat(const char *restrict pathname, struct stat *restrict buf); int fstat(int fields, struct stat *buf); int lstat(const char *restrict pathname, struct stat *restrict buf);

其中stat函數(shù)的作用是獲取路徑名 path 對應(yīng)的 inode 中的屬性

struct stat st; //存儲 inode 屬性信息 ret = stat(path, &st); //成功返回0,失敗返回-1

還有如下定義:

#define S_IFMT 0170000 #define S_IFSOCK 0140000 #define S_IFLNK 0120000 #define S_IFREG 0100000 #define S_IFBLK 0060000 #define S_IFDIR 0040000 #define S_IFCHR 0020000 #define S_IFIFO 0010000 #define S_ISUID 0004000 #define S_ISGID 0002000 #define S_ISVTX 0001000#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)

首先S_IFMT是一個(gè)掩碼,它的值是0170000(注意這里用的是八進(jìn)制), 可以用來過濾出前四位表示的文件類型。

其后的連續(xù)七個(gè)分別對應(yīng)套接口文件、符號鏈接文件、普通文件、塊設(shè)備、目錄、字符設(shè)備、管道,它們分別對應(yīng)一個(gè)不同的值。

要判斷一個(gè)文件是不是目錄,首先通過掩碼S_IFMT把其他無關(guān)的部分置0,再與表示目錄的數(shù)值比較,從而判斷這是否是一個(gè)目錄,下面的代碼

if ((info.st_mode & S_IFMT) == S_IFDIR)printf("this is a directory");

為了簡便操作,<sys/stat.h>中提供了宏來代替上述代碼,所以如果需要判斷文件是不是目錄就可以這樣:

if (S_ISDIR(info.st_mode))printf("this is a directory");

實(shí)現(xiàn)步驟

1、實(shí)現(xiàn)核心功能

首先實(shí)現(xiàn)核心功能:遍歷列出普通磁盤文件,包括文件名和文件大小。

先定義兩個(gè)功能函數(shù),分別用于遍歷目錄和打印文件信息,在遍歷目錄的過程中打印文件信息:

void dirwalk(char *dir, void (*func)(char *)); void print_file_info(char *name);

下面來分別實(shí)現(xiàn)這兩個(gè)函數(shù),先實(shí)現(xiàn)dirwalk函數(shù):

/*對目錄中所有文件執(zhí)行print_file_info操作*/ /*把print_file_info函數(shù)作為參數(shù)傳進(jìn)去*/ void dirwalk(char *dir, void (*func)(char *)) {char name[MAX_PATH];struct dirent *dp;DIR *dfd;if ((dfd = opendir(dir)) == NULL) { //打開文件失敗fprintf(stderr, "dirwalk: can't open %s\n", dir);return;}while ((dp = readdir(dfd)) != NULL) { //讀目錄記錄項(xiàng)if (strcmp(dp->d_name, ".") == 0 || strcmp(dp -> d_name, "..") == 0) {continue; //跳過當(dāng)前目錄以及父目錄}//目錄過長if (strlen(dir) + strlen(dp -> d_name) + 2 > sizeof(name)) {fprintf(stderr, "dirwalk : name %s %s too long\n", dir, dp->d_name);}else {sprintf(name, "%s/%s", dir, dp->d_name); //添加子目錄(*func)(name); //打印文件信息}}closedir(dfd); }

然后實(shí)現(xiàn)print_file_info函數(shù):

/*打印文件信息*/ void print_file_info(char *name) {struct stat stbuf;// 獲取文件狀態(tài)并儲存在stbuf結(jié)構(gòu)中if (stat(name, &stbuf) == -1) {fprintf(stderr, "file size: open %s failed\n", name);return;}//如果是目錄遍歷下一級目錄if (S_ISDIR(stbuf.st_mode)) { dirwalk(name, print_file_info); }else {//不是目錄,打印文件size及nameprintf("%8ld %s\n", stbuf.st_size, name);} }

到此就把核心功能實(shí)現(xiàn)了,接下來進(jìn)一步完善功能。

2、添加命令行參數(shù)選項(xiàng)和錯(cuò)誤響應(yīng)

定義一個(gè)結(jié)構(gòu)體記錄參數(shù)選項(xiàng),

struct stu { //0表示未使用,1表示使用int r;int a;int l;int h;int m;int min;int max;int day; }Parameter = {0, 0, 0, 0, 0, -1, -1, -1};

定義一個(gè)新的功能函數(shù)get_parameter,用來獲取參數(shù)選項(xiàng),不考慮完整的錯(cuò)誤分析,

/*分析參數(shù),不具體考慮錯(cuò)誤*/ void get_parameter(int argc, char *argv[]) {for (int i = 1; i < argc; i++) { //逐個(gè)分析命令行參數(shù)if (strcmp(argv[i], "-r") == 0) { // -rParameter.r = 1;}else if (strcmp(argv[i], "-a") == 0) { // -aParameter.a = 1;}else if (strcmp(argv[i], "-l") == 0) { // -l minParameter.l = 1;i++;Parameter.min = atoi(argv[i]);}else if (strcmp(argv[i], "-h") == 0) { // -l maxParameter.h = 1;i++;Parameter.max = atoi(argv[i]);}else if (strcmp(argv[i], "-m") == 0) { // -m dayParameter.m = 1;i++;Parameter.day = atoi(argv[i]);}else if (strcmp(argv[i], "--") == 0) { // --i++;if (i == argc) strcpy(path, "."); else if (i = argc - 1) strcpy(path, argv[i]);else error();break;}else if (i = argc - 1) { //不是功能參數(shù),判斷是不是最后一項(xiàng)(路徑)strcpy(path, argv[i]);}else {error();}} }

其中error函數(shù)為錯(cuò)誤響應(yīng)函數(shù),打印參數(shù)提示信息:

void error() {printf("List information about the FILEs (the current directory by default)\n\n");printf(" -? Display this help and exit\n");printf(" -a Do not hide entries starting with .\n");printf(" -r List subdirectories recursively\n");printf(" -l <bytes> Minimum of file size\n");printf(" -h <bytes> Maximum of file size\n");printf(" -m <days> Limit file last modified time\n\n");exit(-1); }

接下來修改dirwalk函數(shù)和print_file_info函數(shù),添加參數(shù)響應(yīng)功能

把dirwalk函數(shù)中打印文件的分支修改如下,添加對 -a 的處理:

else {if (dp->d_name[0] == '.' && Parameter.a == 0) //以.開頭的文件 continue;sprintf(name, "%s/%s", dir, dp->d_name);(*func)(name); }

然后在print_file_info函數(shù)中添加對 -r, -l, -h, -m 的處理:

//如果是目錄 if (S_ISDIR(stbuf.st_mode)) {if (strcmp(name, path) != 0) //不顯示目標(biāo)目錄的信息printf("%8ld %s/\n", stbuf.st_size, name);if (Parameter.r == 1 || strcmp(name, path) == 0) { //如果有 -r 遍歷下一級目錄dirwalk(name, print_file_info);} } else {//不是目錄,根據(jù)-l -h -m打印文件size及nameint flag = 1; //判斷是否要輸出 if (Parameter.l == 1 && stbuf.st_size < Parameter.min) flag = 0;if (Parameter.h == 1 && stbuf.st_size > Parameter.max) flag = 0;if (Parameter.m == 1) {struct timeval nowTime;gettimeofday(&nowTime, NULL);if (nowTime.tv_sec - stbuf.st_mtim.tv_sec > (time_t)(Parameter.day*86400))flag = 0;}if (flag == 1) printf("%8ld %s\n", stbuf.st_size, name); }

這樣代碼就完成啦,完整代碼見附錄

3、測試

使用命令vi list.c編寫代碼并保存后,利用命令gcc list.c -o list編譯成可執(zhí)行文件,開始測試

  • 先執(zhí)行l(wèi)s命令,再執(zhí)行簡單的./list命令,對比正確

  • 執(zhí)行l(wèi)s -a命令,再執(zhí)行./list -a命令,對比正確

  • 執(zhí)行./list -r命令,結(jié)果正確

  • 執(zhí)行./list -r -l 4000 -h 20000 temp命令,結(jié)果正確

  • 執(zhí)行./list -- -a命令,結(jié)果顯示不存在該文件,正確

代碼

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <dirent.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/time.h>#define MAX_PATH 512 //最大文件長度定義為512struct stu { //0表示未使用,1表示使用int r;int a;int l;int h;int m;int min;int max;int day; }Parameter = {0, 0, 0, 0, 0, -1, -1, -1};char path[MAX_PATH] = ".";void dirwalk(char *dir, void (*func)(char *)); void print_file_info(char *name); void get_parameter(int argc, char *argv[]); void error();/*對目錄中所有文件執(zhí)行print_file_info操作*/ /*把print_file_info函數(shù)作為參數(shù)傳進(jìn)去*/ void dirwalk(char *dir, void (*func)(char *)) {char name[MAX_PATH];struct dirent *dp;DIR *dfd;if ((dfd = opendir(dir)) == NULL) {fprintf(stderr, "dirwalk: can't open %s\n", dir);return;}while ((dp = readdir(dfd)) != NULL) { //讀目錄記錄項(xiàng)if (strcmp(dp->d_name, ".") == 0 || strcmp(dp -> d_name, "..") == 0) {continue; //跳過當(dāng)前目錄以及父目錄}if (strlen(dir) + strlen(dp -> d_name) + 2 > sizeof(name)) {fprintf(stderr, "dirwalk : name %s %s too long\n", dir, dp->d_name);}else {if (dp->d_name[0] == '.' && Parameter.a == 0) //以.開頭的文件 continue;sprintf(name, "%s/%s", dir, dp->d_name);(*func)(name);}}closedir(dfd); }/*打印文件信息*/ void print_file_info(char *name) {struct stat stbuf;// 獲取文件狀態(tài)并儲存在stbuf結(jié)構(gòu)中if (stat(name, &stbuf) == -1) {fprintf(stderr, "file size: open %s failed\n", name);return;}//如果是目錄if (S_ISDIR(stbuf.st_mode)) {if (strcmp(name, path) != 0)printf("%8ld %s/\n", stbuf.st_size, name);if (Parameter.r == 1 || strcmp(name, path) == 0) { //如果有 -r 遍歷下一級目錄dirwalk(name, print_file_info);}}else {//不是目錄,根據(jù)-l -h -m打印文件size及nameint flag = 1; //判斷是否要輸出 if (Parameter.l == 1 && stbuf.st_size < Parameter.min) flag = 0;if (Parameter.h == 1 && stbuf.st_size > Parameter.max) flag = 0;if (Parameter.m == 1) {struct timeval nowTime;gettimeofday(&nowTime, NULL);if (nowTime.tv_sec - stbuf.st_mtim.tv_sec > (time_t)(Parameter.day*86400))flag = 0;}if (flag == 1) printf("%8ld %s\n", stbuf.st_size, name);} }/*分析參數(shù),不具體考慮錯(cuò)誤*/ void get_parameter(int argc, char *argv[]) {for (int i = 1; i < argc; i++) {if (strcmp(argv[i], "-r") == 0) {Parameter.r = 1;}else if (strcmp(argv[i], "-a") == 0) {Parameter.a = 1;}else if (strcmp(argv[i], "-l") == 0) {Parameter.l = 1;i++;Parameter.min = atoi(argv[i]);}else if (strcmp(argv[i], "-h") == 0) {Parameter.h = 1;i++;Parameter.max = atoi(argv[i]);}else if (strcmp(argv[i], "-m") == 0) {Parameter.m = 1;i++;Parameter.day = atoi(argv[i]);}else if (strcmp(argv[i], "--") == 0) {i++;if (i == argc) strcpy(path, "."); else if (i = argc - 1) strcpy(path, argv[i]);else error();break;}else if (i = argc - 1) {strcpy(path, argv[i]);}else {error();}} }void error() {printf("List information about the FILEs (the current directory by default)\n\n");printf(" -? Display this help and exit\n");printf(" -a Do not hide entries starting with .\n");printf(" -r List subdirectories recursively\n");printf(" -l <bytes> Minimum of file size\n");printf(" -h <bytes> Maximum of file size\n");printf(" -m <days> Limit file last modified time\n\n");exit(-1); }int main(int argc, char *argv[]) {get_parameter(argc, argv);printf("file size file name\n");print_file_info(path);return 0; }

參考來源:
https://blog.csdn.net/astrotycoon/article/details/8679676
https://blog.csdn.net/y396397735/article/details/50640919

總結(jié)

以上是生活随笔為你收集整理的Linux目录遍历实现,列出目录下文件,可使用部分参数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。