Linux-C 遍历目录,复制目录
一、简述
记--递归方法遍历目录,复制目录,也可以利用强大的shell命令获取目录下指定格式的文件。
二、遍历目录例子
1、递归方法
测试代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <libgen.h>
/*
*display_dir:递归遍历目录,打印所有文件路径名
*@dir_path:目录路径
*
*/
void display_dir( char *dir_path )
{
//排除是"."目录、".."目录 (在Linux,每个目录都有"."目录、".."目录,"."表示当前目录,".."是上级目录)
if( strcmp( dir_path, "." ) == 0 || strcmp( dir_path, ".." ) == 0 )
{
return;
}
DIR *dir_ptr;//目录指针
struct dirent *file_info;//目录项指针,存放目录项的相关信息比如文件类型
dir_ptr = opendir( dir_path );//打开目录
if( dir_ptr == NULL )
{
return ;
}
//为了统一输出方式,比如要打开的目录a里面有个1.txt,
//传目录a和传a/进来都显示a/1.txt,而不会一个是a//1.txt
int dir_len = strlen( dir_path );//Linux兼容 a/1.txt 和 a//1.txt
if( dir_path[dir_len-1] == '/')
{
dir_path[dir_len-1] = '\0';
}
char sub_dir[512] = {0};//临时存放子目录名称
while( file_info = readdir( dir_ptr ) )//每次循环读取一个目录项(一个文件)
{
switch( file_info->d_type )//根据文件类型执行相应动作,
{
case DT_DIR: //如果是目录就递归遍历
if( strcmp( file_info->d_name, ".") != 0 && strcmp(file_info->d_name, "..") != 0 )
{
sprintf( sub_dir, "%s/%s", dir_path, file_info->d_name );
display_dir( sub_dir );
}
break;
case DT_BLK:
case DT_CHR:
case DT_FIFO:
case DT_LNK:
case DT_REG: //常规文件 .txt .bmp .jpg .c 可执行文件 等等
case DT_SOCK:
case DT_UNKNOWN:printf( "%s/%s\n", dir_path, file_info->d_name );//其他文件直接显示
break;
default:
break;
}
}
closedir( dir_ptr );//关闭目录
}
int main(int argc, char *argv[])
{
//main函数参数在执行时传进来,比如./hello jack argc=2,argc[0]=./hello,argv[1]=jack
if(argc != 2)
{
printf("argc error!\n");
return -1;
}
display_dir( argv[1] );//调用目录打印函数
return 0;
}
运行效果
2、利用shell命令
#!/bin/bash
#Date:2019-11-16
dirCnt=0
fileCnt=0
#display files of dir
function displayDir()
{
#check args
if [ $# -lt 1 ]
then
echo "args err."
return 0
fi
#check dir
local dir=$1
if [ -z "$dir" ]
then
echo "dir err."
return 0
fi
if [ ! -d "$dir" ]
then
#echo "not found $dir."
return 0
fi
#displsy files
for file in `ls $dir`
do
local fileName=$dir/$file
if [ ! -d "$fileName" ]
then
echo "$fileName"
let fileCnt=fileCnt+1
else
displayDir "$fileName"
let dirCnt=dirCnt+1
fi
done
return 1
}
displayDir $1
echo -e "\n$dirCnt directories, $fileCnt files"
结果:
三、复制目录
程序将要复制的目录路径dir1 复制到 目标路径dir2下。
测试代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string.h>
#include <libgen.h>
void copy_file(char *dest_dir, char *src_dir, char * filename )
{
char tmp_src_dir[512] = {0};
char tmp_dest_dir[512] = {0};
sprintf( tmp_dest_dir, "%s/%s", dest_dir, filename );
sprintf( tmp_src_dir, "%s/%s", src_dir, filename );
FILE *src_fp = fopen( tmp_src_dir ,"r" );
if(!src_fp)
{
perror("open file error!");
return ;
}
FILE *dest_fp = fopen( tmp_dest_dir, "w");
if(!dest_fp)
{
perror("open file error!");
return ;
}
char buffer[1024*128];
char *tmp;
int rd_ret;
int wr_ret;
while(1)
{
rd_ret = fread(buffer, 1, sizeof(buffer), src_fp);
if(rd_ret == 0 )
{
break;
}
tmp = buffer;
while(1)
{
wr_ret = fwrite(tmp, 1, rd_ret, dest_fp);
if(wr_ret == rd_ret)
{
break;
}
else
{
rd_ret -= wr_ret;
tmp += wr_ret;
}
}
}
}
void _copy_dir( char *src_dir_path, char *dest_dir_path )
{
if( strcmp( src_dir_path, "." ) == 0 || strcmp( src_dir_path, ".." ) == 0 )
{
return;
}
DIR *src_dp, *dest_dp;
struct dirent *file_info;
src_dp = opendir( src_dir_path );
if( src_dp == NULL )
{
return ;
}
int dir_len = strlen( src_dir_path );
if( src_dir_path[dir_len-1] == '/')
{
src_dir_path[dir_len-1] = '\0';
}
dir_len = strlen( dest_dir_path );
if( dest_dir_path[dir_len-1] == '/')
{
src_dir_path[dir_len-1] = '\0';
}
char tmp_src_dir[512] = {0};
char tmp_dest_dir[512] = {0};
sprintf( tmp_dest_dir, "%s/%s", dest_dir_path, basename( src_dir_path ) );
dest_dp = opendir( tmp_dest_dir );
if( dest_dp == NULL )
{
mkdir( tmp_dest_dir, 0777);
}
else
{
closedir( dest_dp );
}
while( file_info = readdir( src_dp ) )
{
switch( file_info->d_type )
{
case DT_DIR:
if( strcmp( file_info->d_name, ".") != 0 && strcmp(file_info->d_name, "..") != 0 )
{
sprintf( tmp_src_dir, "%s/%s", src_dir_path, file_info->d_name );
_copy_dir( tmp_src_dir, tmp_dest_dir );
}
break;
case DT_BLK:
case DT_CHR:
case DT_FIFO:
case DT_LNK:
case DT_REG:
case DT_SOCK:;
case DT_UNKNOWN:copy_file( tmp_dest_dir, src_dir_path, file_info->d_name);
break;
default:
break;
}
}
closedir( src_dp );
}
void copy_dir( char *src_dir_path, char *dest_dir_path )
{
DIR *dest_dp;
dest_dp = opendir( dest_dir_path );
if( dest_dp == NULL )
{
if( mkdir( dest_dir_path, 0777 ) == -1 )
{
perror( "mkdir error!\n" );
return ;
}
}
else
{
closedir( dest_dp );
}
_copy_dir( src_dir_path, dest_dir_path );
}
int main(int argc, char *argv[])
{
if(argc != 3)
{
printf("argc error!\n");
return -1;
}
copy_dir(argv[1], argv[2]);
return 0;
}
运行结果:
四、总结
1、opendir()函数
在第三本man手册,在终端输入命令:man 3 opendir 进行查询
函数原型及头文件
函数返回值,成功返回目录指针,失败返回NULL并设置全局错误号
2、readdir()函数
在第三本man手册,在终端输入命令:man 3 readdir 进行查询
函数原型及头文件
返回值
成功时,readdir()返回指向dirent结构的指针。 (这种结构可能是静态分配的;不要试图释放它。)
如果到达目录流的末尾,则返回NULL并且不更改errno。 如果发生错误,则返回NULL并正确设置errno。 要区分流的结尾和错误,请在调用readdir()之前将errno设置为零,然后检查errno的值是否返回NULL。
目录项结构体struct drient
其中的d_type就是文件类型