ls用於列舉目錄內容,要實現這個功能,毫無疑問,需要讀取目錄,涉及到兩個api: opendir:DIR *opendir(const char *name), 傳文件名,返回一個指針,指向目錄序列 readdir:struct dirent *readdir(DIR *dirp), 把opendi ...
ls用於列舉目錄內容,要實現這個功能,毫無疑問,需要讀取目錄,涉及到兩個api:
opendir:DIR *opendir(const char *name), 傳文件名,返回一個指針,指向目錄序列
readdir:struct dirent *readdir(DIR *dirp), 把opendir的返回值傳過來, 返回值為一個結構體
struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* not an offset; see NOTES */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all filesystem types */ char d_name[256]; /* filename */ };
有了這兩個api,就可以實現一個簡易的ls功能
1 /*================================================================ 2 * Copyright (C) 2018 . All rights reserved. 3 * 4 * 文件名稱:myls.c 5 * 創 建 者:ghostwu(吳華) 6 * 創建日期:2018年01月09日 7 * 描 述: ls命令 8 * 9 ================================================================*/ 10 11 #include <stdio.h> 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include <stdlib.h> 15 16 void do_ls( char [] ); 17 18 int main(int argc, char *argv[]) 19 { 20 if( argc == 1 ) { 21 do_ls( "." ); 22 }else { 23 while( --argc ) { 24 printf( "arg=%s\n", * ++argv ); 25 do_ls( *argv ); 26 } 27 } 28 return 0; 29 } 30 31 void do_ls( char dir_entry[] ) { 32 DIR* pDir; 33 struct dirent* pCurDir; 34 if( ( pDir = opendir( dir_entry ) ) == NULL ){ 35 perror( "read dir" ); 36 exit( -1 ); 37 }else { 38 while( ( pCurDir = readdir( pDir ) ) != NULL ) { 39 printf( "%s\n", pCurDir->d_name ); 40 } 41 } 42 }View Code
這個簡易的ls功能,列舉出了所有的文件( 包括隱藏的 ), 但是很多的信息不全,如: 許可權,用戶和組,修改時間,文件大小,鏈接數目等,stat這個api可以獲取文件的這些信息
stat:獲取文件狀態信息
原型:int stat(const char *pathname, struct stat *buf), 第一個參數:文件名, 第二個參數:保存文件狀態信息的結構體( man 2 stat 有結構體相關說明 )
1、獲取文件的大小
1 /*================================================================ 2 * Copyright (C) 2018 . All rights reserved. 3 * 4 * 文件名稱:stat.c 5 * 創 建 者:ghostwu(吳華) 6 * 創建日期:2018年01月09日 7 * 描 述: 8 * 9 ================================================================*/ 10 11 #include <stdio.h> 12 #include <sys/stat.h> 13 14 #define FILENAME "/etc/passwd" 15 16 int main(int argc, char *argv[]) 17 { 18 struct stat filestat; 19 20 if( -1 == stat( FILENAME, &filestat ) ) { 21 perror( "file stat" ); 22 return -1; 23 }else { 24 printf( "the size of %s is %ld\n",FILENAME, filestat.st_size ); 25 } 26 27 return 0; 28 }View Code
2、讀取文件st_mode(許可權位), 用戶id, 組id, 修改時間,鏈接數目
1 /*================================================================ 2 * Copyright (C) 2018 . All rights reserved. 3 * 4 * 文件名稱:stat2.c 5 * 創 建 者:ghostwu(吳華) 6 * 創建日期:2018年01月09日 7 * 描 述: 8 * 9 ================================================================*/ 10 11 #include <stdio.h> 12 #include <sys/stat.h> 13 #include <string.h> 14 #include <time.h> 15 16 void show_info( char *file, struct stat* statinfo ); 17 void show_time( time_t filetime ); 18 char* format_time( char* dsttime, const char* srctime ); 19 20 int main(int argc, char *argv[]) 21 { 22 struct stat fileinfo; 23 if( argc > 1 ) { 24 /*調試信息 25 printf( "%s\n", argv[1] ); 26 int res = stat( argv[1], &fileinfo ); 27 printf( "%d\n", res ); 28 */ 29 if( stat( argv[1], &fileinfo ) != -1 ) { 30 show_info( argv[1], &fileinfo ); 31 } 32 }else { 33 perror( "get args from terminal" ); 34 } 35 36 return 0; 37 } 38 39 void show_info( char* file, struct stat* statinfo ){ 40 printf( "%s文件信息如下:\n", file ); 41 printf( "st_mode = %d\n", statinfo->st_mode ); 42 printf( "links = %ld\n", statinfo->st_nlink ); 43 printf( "uid = %d\n", statinfo->st_uid ); 44 printf( "gid = %d\n", statinfo->st_gid ); 45 printf( "file size = %ld\n", statinfo->st_size ); 46 show_time( statinfo->st_mtime ); 47 } 48 49 void show_time( time_t filetime ) { 50 struct tm* ptm; 51 ptm = localtime( &filetime ); 52 53 int month = ptm->tm_mon + 1; 54 int day = ptm->tm_mday; 55 int hour = ptm->tm_hour; 56 int min = ptm->tm_min; 57 58 char srchour[3] = "0"; 59 char srcmin[3] = "0"; 60 char dsthour[3] = "0"; 61 char dstmin[3] = "0"; 62 sprintf( srchour, "%d", hour ); 63 sprintf( srcmin, "%d", min ); 64 format_time( dsthour, srchour ); 65 format_time( dstmin, srcmin ); 66 67 printf( "文件最後修改時間: %d月\t%d\t%s:%s\n", month, day, dsthour, dstmin ); 68 } 69 70 char* format_time( char* dsttime, const char* srctime ) { 71 if( strlen( srctime ) < 2 ) { 72 return strcat( dsttime, srctime ); 73 } 74 return strcpy( dsttime, srctime ); 75 }View Code
3、許可權st_mode轉字元許可權位( 如: -rwxrwxrwx ), 用戶id和組id轉用戶名和組名稱,判斷文件類型
1 /*================================================================ 2 * Copyright (C) 2018 . All rights reserved. 3 * 4 * 文件名稱:stat3.c 5 * 創 建 者:ghostwu(吳華) 6 * 創建日期:2018年01月09日 7 * 描 述:文件類型與許可權位 8 * 9 ================================================================*/ 10 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <sys/stat.h> 14 #include <string.h> 15 #include <sys/types.h> 16 #include <pwd.h> 17 #include <grp.h> 18 19 void do_ls( char* filename ); 20 void show_filetype( char* filename, int filemode ); 21 void show_filetype2( char* filename, int filemode ); 22 void mode_to_letters( int filemode, char str[] ); 23 //用戶id轉名稱 24 char* uid_to_name( uid_t uid ); 25 //組id轉名稱 26 char* gid_to_name( gid_t gid ); 27 28 int main(int argc, char *argv[]) 29 { 30 if( argc < 2 ) { 31 printf( "usage:%s file\n", argv[0] ); 32 return -1; 33 }else { 34 do_ls( argv[1] ); 35 } 36 return 0; 37 } 38 39 char* uid_to_name( uid_t uid ){ 40 return getpwuid( uid )->pw_name; 41 } 42 43 char* gid_to_name( gid_t gid ){ 44 return getgrgid( gid )->gr_name; 45 } 46 47 void do_ls( char* filename ) { 48 struct stat fileinfo; 49 if( stat( filename, &fileinfo ) == -1 ) { 50 printf( "%s open failure\n", filename ); 51 exit( -1 ); 52 } 53 //printf( "st_mode = %d\n", fileinfo.st_mode ); 54 show_filetype( filename, fileinfo.st_mode ); 55 show_filetype2( filename, fileinfo.st_mode ); 56 char file_permission[10]; 57 mode_to_letters( fileinfo.st_mode, file_permission ); 58 printf( "%s\n", file_permission ); 59 printf( "用戶:%s\n", uid_to_name( fileinfo.st_uid ) ); 60 printf( "組:%s\n", gid_to_name( fileinfo.st_gid ) ); 61 } 62 63 //掩碼判斷文件類型 64 void show_filetype( char* filename, int filemode ){ 65 //用st_mode的值跟0170000這個掩碼相位與的結果 判斷文件類型 66 if ( ( filemode & 0170000 ) == 0100000 ){ 67 printf( "%s是普通文件\n", filename ); 68 }else if( ( filemode & 0170000 ) == 0040000 ){ 69 printf( "%s是目錄\n", filename ); 70 }else if ( ( filemode & S_IFMT ) == S_IFLNK ){ 71 printf( "%s是符號鏈接\n", filename ); 72 } 73 } 74 75 //用巨集判斷文件類型 76 void show_filetype2( char* filename, int filemode ){ 77 if( S_ISREG( filemode ) ) { 78 printf( "%s是普通文件\n", filename ); 79 }else if( S_ISDIR( filemode ) ) { 80 printf( "%s是目錄\n", filename ); 81 }else if( S_ISLNK( filemode ) ){ 82 printf( "%s是符號鏈接\n", filename ); 83 } 84 } 85 86 //數字解碼成字母許可權位 87 void mode_to_letters( int filemode, char str[] ) { 88 strcpy( str, "----------" ); 89 if( S_ISREG( filemode ) ) str[0] = '-'; 90 if( S_ISDIR( filemode ) ) str[0] = 'd'; 91 if( S_ISLNK( filemode ) ) str[0] = 'l'; 92 93 //用戶許可權位 94 if( filemode & S_IRUSR ) str[1] = 'r'; 95 if( filemode & S_IWUSR ) str[2] = 'w'; 96 if( filemode & S_IXUSR ) str[3] = 'x'; 97 98 //組許可權位 99 if( filemode & S_IRGRP ) str[4] = 'r'; 100 if( filemode & S_IWGRP ) str[5] = 'w'; 101 if( filemode & S_IXGRP ) str[6] = 'x'; 102 103 //其他組許可權位 104 if( filemode & S_IROTH ) str[7] = 'r'; 105 if( filemode & S_IWOTH ) str[8] = 'w'; 106 if( filemode & S_IXOTH ) str[9] = 'x'; 107 }View Code
綜合上面3個小實例,可以得到格式化比較好的ls命令版本:
1 /*================================================================ 2 * Copyright (C) 2018 . All rights reserved. 3 * 4 * 文件名稱:myls2.c 5 * 創 建 者:ghostwu(吳華) 6 * 創建日期:2018年01月09日 7 * 描 述:ls命令( version 1.2 ) 8 * 9 ================================================================*/ 10 11 #include <stdio.h> 12 #include <sys/types.h> 13 #include <dirent.h> 14 #include <stdlib.h> 15 #include <sys/types.h> 16 #include <sys/stat.h> 17 #include <unistd.h> 18 #include <string.h> 19 #include <sys/types.h> 20 #include <pwd.h> 21 #include <grp.h> 22 #include <time.h> 23 24 void do_ls( char [] ); 25 void do_stat( char* filename ); 26 void show_list( char* filename, struct stat* statinfo ); 27 void mode_to_letters( mode_t filemode, char str[] ); 28 void show_time( time_t filetime ); 29 char* format_time( char* dsttime, const char* srctime ); 30 31 //用戶id轉名稱 32 char* uid_to_name( uid_t uid ); 33 //組id轉名稱 34 char* gid_to_name( gid_t gid ); 35 36 int main(int argc, char *argv[]) 37 { 38 if( argc == 1 ) { 39 do_ls( "." ); 40 }else { 41 while( --argc ) { 42 printf( "arg=%s\n", * ++argv ); 43 do_ls( *argv ); 44 } 45 } 46 return 0; 47 } 48 49 void do_ls( char dir_entry[] ) { 50 DIR* pDir; 51 struct dirent* pCurDir; 52 if( ( pDir = opendir( dir_entry ) ) == NULL ){ 53 perror( "read dir" ); 54 exit( -1 ); 55 }else { 56 while( ( pCurDir = readdir( pDir ) ) != NULL ) { 57 do_stat( pCurDir->d_name ); 58 } 59 closedir( pDir ); 60 } 61 } 62 63 //得到文件信息 64 void do_stat( char* filename ){ 65 struct stat statinfo; 66 if ( stat( filename, &statinfo ) == -1 ) { 67 printf( "打開%s失敗\n", filename ); 68 exit( -1 ); 69 }else { 70 show_list( filename, &statinfo ); 71 } 72 } 73 74 //顯示文件列表 75 void show_list( char* filename, struct stat* statinfo ) { 76 mode_t st_mode = statinfo->st_mode; 77 78 char str[10]; 79 mode_to_letters( st_mode, str ); 80 printf( "%s\t", str ); 81 82 printf( "%ld\t", statinfo->st_nlink ); //符號鏈接 83 printf( "%s\t\t", uid_to_name( statinfo->st_uid ) ); //用戶名 84 printf( "%s\t", gid_to_name( statinfo->st_gid ) ); //組名 85 printf( "%10ld", statinfo->st_size ); //文件大小 86 show_time( statinfo->st_mtime ); //最後一次修改時間 87 printf( "\t%s", filename ); 88 89 printf( "\n" ); 90 } 91 92 char* uid_to_name( uid_t uid ){ 93 return getpwuid( uid )->pw_name; 94 } 95 96 char* gid_to_name( gid_t gid ){ 97 return getgrgid( gid )->gr_name; 98 } 99 100 void mode_to_letters( mode_t filemode, char str[] ) { 101 102 strcpy( str, "----------" ); 103 if( S_ISREG( filemode ) ) str[0] = '-'; 104 if( S_ISDIR( filemode ) ) str[0] = 'd'; 105 if( S_ISLNK( filemode ) ) str[0] = 'l'; 106 107 //用戶許可權位 108 if( filemode & S_IRUSR ) str[1] = 'r'; 109 if( filemode & S_IWUSR ) str[2] = 'w'; 110 if( filemode & S_IXUSR ) str[3] = 'x'; 111 112 //組許可權位 113 if( filemode & S_IRGRP ) str[4] = 'r'; 114 if( filemode & S_IWGRP ) str[5] = 'w'; 115 if( filemode & S_IXGRP ) str[6] = 'x'; 116 117 //其他組許可權位 118 if( filemode & S_IROTH ) str[7] = 'r'; 119 if( filemode & S_IWOTH ) str[8] = 'w'; 120 if( filemode & S_IXOTH ) str[9] = 'x'; 121 } 122 123 void show_time( time_t filetime ) { 124 struct tm* ptm; 125 ptm = localtime( &filetime ); 126 127 int month = ptm->tm_mon + 1; 128 int day = ptm->tm_mday; 129 int hour = ptm->tm_hour; 130 int min = ptm->tm_min; 131 132 char srchour[3] = "0"; 133 char srcmin[3] = "0"; 134 char dsthour[3] = "0"; 135 char dstmin[3] = "0"; 136 sprintf( srchour, "%d", hour ); 137 sprintf( srcmin, "%d", min ); 138 format_time( dsthour, srchour ); 139 format_time( dstmin, srcmin ); 140 141 printf( "%4d月%4d%4s:%2s", month, day, dsthour, dstmin ); 142 } 143 144 char* format_time( char* dsttime, const char* srctime ) { 145 if( strlen( srctime ) < 2 ) { 146 return strcat( dsttime, srctime ); 147 } 148 return strcpy( dsttime, srctime ); 149 }View Code
總結:
1)opendir和readdir的用法
2)結構體struct dirent的應用
3)stat的用法