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;
}

        运行效果


linux环境java遍历文件目录 linux遍历目录命令_sed

       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"

       结果:

          

linux环境java遍历文件目录 linux遍历目录命令_遍历目录_02

三、复制目录

       程序将要复制的目录路径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;
}

       运行结果:     

linux环境java遍历文件目录 linux遍历目录命令_遍历目录_03

      

linux环境java遍历文件目录 linux遍历目录命令_复制目录_04

四、总结

      1、opendir()函数

           在第三本man手册,在终端输入命令:man 3 opendir 进行查询

          函数原型及头文件          

linux环境java遍历文件目录 linux遍历目录命令_复制目录_05

         函数返回值,成功返回目录指针,失败返回NULL并设置全局错误号         

linux环境java遍历文件目录 linux遍历目录命令_#include_06

 2、readdir()函数

        在第三本man手册,在终端输入命令:man 3 readdir 进行查询

       函数原型及头文件

       

linux环境java遍历文件目录 linux遍历目录命令_遍历目录_07

       返回值       

linux环境java遍历文件目录 linux遍历目录命令_#include_08

       成功时,readdir()返回指向dirent结构的指针。 (这种结构可能是静态分配的;不要试图释放它。)
        如果到达目录流的末尾,则返回NULL并且不更改errno。 如果发生错误,则返回NULL并正确设置errno。 要区分流的结尾和错误,请在调用readdir()之前将errno设置为零,然后检查errno的值是否返回NULL。

      目录项结构体struct drient      

linux环境java遍历文件目录 linux遍历目录命令_遍历目录_09

      其中的d_type就是文件类型     

linux环境java遍历文件目录 linux遍历目录命令_#include_10