一、前言
之前有幾篇文章介紹了Linux下檔案程式設計,那麼目錄和檔案程式設計類似,也有一套函數,可以打開,讀取、建立目錄等。建立目錄、檔案除了指令以外(
mkdir、touch
),都有對應的函數實作相同功能。
使用較多的就是周遊目錄的功能,比如: 音樂播放器需要循環播放指定目錄下所有音頻檔案,視訊播放器需要周遊指定目錄查找所有的視訊檔案加入到播放清單等等。
目錄操作相關函數如下:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
函數功能: 打開目錄
函數形參:
const char *name :打開的目錄路徑
傳回值: 目錄打開成功傳回指向該目錄的指針.
struct dirent *readdir(DIR *dirp);
函數功能: 讀目錄. 每調用一次就擷取一次目前目錄下一個檔案的資訊.
函數形參:
DIR *dirp :打開的目錄指針.
傳回值:儲存目前讀取成功的檔案資訊.
該函數可以重複調用,調用成功就傳回目前目錄下一個檔案的資訊,如果讀取失敗或者檔案讀取完畢傳回NULL。
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; not supported
by all file system types */
char d_name[256]; /* filename */
};
int closedir(DIR *dirp);
函數功能: 關閉已經打開的目錄.
#include <sys/stat.h>
#include <sys/types.h>
int mkdir(const char *pathname, mode_t mode);
函數功能: 建立一個新目錄.
二、案例代碼
2.1 周遊指定目錄: 實作ls -a指令功能
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("參數: ./a.out <目錄的路徑>\n");
return 0;
}
/*1. 打開目錄*/
DIR *dir=opendir(argv[1]);
if(dir==NULL)
{
printf("%s 目錄打開失敗.\n",argv[1]);
return -1;
}
/*2. 周遊目錄*/
struct dirent *dir_info;
while(dir_info=readdir(dir))
{
printf("%s ",dir_info->d_name);
}
printf("\n");
/*3. 關閉目錄*/
closedir(dir);
return 0;
}
2.2 建立目錄
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("參數: ./a.out <建立的新目錄名稱>\n");
return 0;
}
printf("即将建立的新目錄名稱:%s\n",argv[1]);
/*1. 調用mkdir函數建立目錄*/
// printf("mkdir函數狀态:%d\n",mkdir(argv[1],S_IWUSR|S_IRUSR));
// 成功傳回為0 失敗傳回-1 ,該函數不能建立多層目錄
/*2. 使用system函數調用系統指令完成目錄的建立*/
char cmd_buf[100];
sprintf(cmd_buf,"mkdir %s -p",argv[1]);
system(cmd_buf);
return 0;
}
2.3 得到檔案和目錄的名稱
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <stdlib.h>
#include <libgen.h>
int main(int argc,char **argv)
{
if(argc!=2)
{
printf("參數: ./a.out <路徑>\n");
return 0;
}
//printf("目錄名稱:%s\n",dirname(argv[1]));
//傳入: /123/456/789/a.c 傳回/123/456/789
printf("檔案名稱:%s\n",basename(argv[1]));
//傳入: /123/456/789/a.c 傳回a.c
return 0;
}
2.4 指令行*.c傳參的問題
#include <stdio.h>
int main(int argc,char **argv)
{
int i;
for(i=0;i<argc;i++)
printf("%s\n",argv[i]);
return 0;
}
[wbyq@wbyq linux_c]$ ./a.out *.c
./a.out
123.c
456.c
app.c
[wbyq@wbyq linux_c]$ ./a.out \*.c
./a.out
*.c
[wbyq@wbyq linux_c]$
2.5 使用目錄操作函數實作ls *.c
使用目錄操作函數實作ls .c 或者ls .mp3 類似的功能.
*号是特殊符号. 是通配符符号。
./a.out \*.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
int main(int argc,char **argv)
{
if(argc!=3)
{
printf("參數: ./a.out <目錄的路徑> <字尾例如:.c .mp3>\n");
return 0;
}
/*1. 打開目錄*/
DIR *dir=opendir(argv[1]);
if(dir==NULL)
{
printf("%s 目錄打開失敗.\n",argv[1]);
return -1;
}
/*2. 周遊目錄*/
struct dirent *dir_info;
struct stat s_buf; //存放狀态資訊的
char *abs_path=NULL;
while(dir_info=readdir(dir))
{
if(strstr(dir_info->d_name,argv[2]))
{
//1. 申請空間
abs_path=malloc(strlen(argv[1])+strlen(dir_info->d_name)+1);
//2. 拼接路徑
sprintf(abs_path,"%s%s",argv[1],dir_info->d_name);
printf("%s\n",abs_path);
//3. 釋放空間
free(abs_path);
}
}
/*3. 關閉目錄*/
closedir(dir);
return 0;
}
2.6 拷貝單層目錄
實作cp指令的功能. 支援拷貝單層目錄.
例如: cp 123.c 456.c 或者 cp abc/ work/ -a
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
int cp_file(const char *src_file,const char *new_file);
int main(int argc,char **argv)
{
if(argc!=3)
{
printf("參數: ./a.out <源目錄的路徑> <目标目錄的路徑>\n");
return 0;
}
/*1. 打開目錄*/
DIR *dir=opendir(argv[1]);
if(dir==NULL)
{
printf("%s 目錄打開失敗.\n",argv[1]);
return -1;
}
/*2. 周遊目錄*/
struct dirent *dir_info;
struct stat s_buf; //存放狀态資訊的
char *abs_path=NULL;
char *new_abs_path=NULL;
while(dir_info=readdir(dir))
{
//1. 申請空間
abs_path=malloc(strlen(argv[1])+strlen(dir_info->d_name)+1);
//2. 拼接路徑
sprintf(abs_path,"%s%s",argv[1],dir_info->d_name);
//3.判斷檔案的類型
stat(abs_path,&s_buf);
if(S_ISREG(s_buf.st_mode)) //普通檔案
{
new_abs_path=malloc(strlen(argv[2])+strlen(dir_info->d_name)+1);
sprintf(new_abs_path,"%s%s",argv[2],dir_info->d_name);
cp_file(abs_path,new_abs_path);
free(new_abs_path);
}
//4. 釋放空間
free(abs_path);
}
/*3. 關閉目錄*/
closedir(dir);
return 0;
}
/*
函數功能: 拷貝指定的檔案
*/
int cp_file(const char *src_file,const char *new_file)
{
/*1. 打開源檔案*/
FILE *src_fp=fopen(src_file,"rb");
if(src_fp==NULL)return -1;
/*2. 建立新檔案*/
FILE *new_fp=fopen(new_file,"wb");
if(new_fp==NULL)return -2;
/*3. 拷貝檔案*/
unsigned char buff[1024];
int cnt;
while(1)
{
cnt=fread(buff,1,1024,src_fp);
fwrite(buff,1,cnt,new_fp);
if(cnt!=1024)break;
}
/*4. 關閉檔案*/
fclose(new_fp);
fclose(src_fp);
return 0;
}