基于线程池的目录拷贝项目
1.功能描述
1)实现文件与文件的拷贝
2)实现目录与目录的拷贝
3)文件与文件的复制 目标文件是否可以绝对/相对路径复制
4)目录与目录的复制 目标目录是否可以绝对/相对路径复制
5)能根据实际情况实现特定要求下的拷贝操作
2.系统框架
>bin
-copy
>doc
-readme.md
>inc
-my_head.h
-thread_pool.h
>lib
>src
-main.c
-copy.c
-fileture.c
-isDir.c
-isFile.c
-isFiletoDir.c
-thread_pool.c
>Makefile
3.模块代码
my_head.h
# ifndef _MY_HEAD_H_
# define _MY_HEAD_H_
# define PATHSIZE 1024
# include "thread_pool.h"
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/mman.h>
# include <dirent.h>
# include <unistd.h>
# include <string.h>
typedef struct file_name
{
char src[ PATHSIZE] ;
char dst[ PATHSIZE] ;
} file_name;
unsigned long total_size;
bool copydir ( thread_pool * pool, char * src, char * dst, struct stat * info) ;
void copyfile ( int src, int dst) ;
void * mytask ( void * arg) ;
void cal_file_size ( char * srcDir) ;
int filetrue ( char * src_file) ;
void Isfile ( struct stat * source_file, struct stat * target_file, thread_pool * pool, char * src_file, char * dst_file) ;
void Isdir ( struct stat * source_file, struct stat * target_file, thread_pool * pool, char * src_file, char * dst_file) ;
void IsfileTodir ( struct stat * source_file, struct stat * target_file, thread_pool * pool, char * src_file, char * dst_file) ;
# endif
thread_pool.h
# ifndef _THREAD_POOL_H_
# define _THREAD_POOL_H_
# define MAX_WAITING_TASKS 1000
# define MAX_ACTIVE_THREADS 20
# include <stdio.h>
# include <stdbool.h>
# include <stdlib.h>
# include <errno.h>
# include <string.h>
# include <pthread.h>
struct task
{
void * ( * do_task) ( void * arg) ;
void * arg;
struct task * next;
} ;
typedef struct thread_pool
{
pthread_mutex_t lock;
pthread_cond_t cond;
bool shutdown;
struct task * task_list;
pthread_t * tids;
unsigned max_waiting_tasks;
unsigned waiting_tasks;
unsigned active_threads;
} thread_pool;
bool init_pool ( thread_pool * pool, unsigned int threads_number) ;
bool add_task ( thread_pool * pool, void * ( * do_task) ( void * arg) , void * task) ;
int add_thread ( thread_pool * pool, unsigned int additional_threads_number) ;
int remove_thread ( thread_pool * pool, unsigned int removing_threads_number) ;
bool destroy_pool ( thread_pool * pool) ;
void * routine ( void * arg) ;
# endif
main.c
# include "my_head.h"
# include "thread_pool.h"
int main ( int argc, char * argv[ ] )
{
thread_pool * pool = malloc ( sizeof ( thread_pool) ) ;
init_pool ( pool, 10 ) ;
if ( argc != 3 )
{
printf ( "Incorrect input format ,Usage: %s getcwd<src> getcwd<dst>\n" , argv[ 0 ] ) ;
return - 1 ;
}
file_name fileName;
strcpy ( fileName. src, argv[ 1 ] ) ;
strcpy ( fileName. dst, argv[ 2 ] ) ;
filetrue ( ( char * ) & fileName. src) ;
struct stat * source_file = malloc ( sizeof ( struct stat ) ) ;
stat ( fileName. src, source_file) ;
struct stat * target_file = malloc ( sizeof ( struct stat ) ) ;
stat ( fileName. dst, target_file) ;
Isfile ( source_file, target_file, pool, ( char * ) & fileName. src, ( char * ) & fileName. dst) ;
Isdir ( source_file, target_file, pool, ( char * ) & fileName. src, ( char * ) & fileName. dst) ;
IsfileTodir ( source_file, target_file, pool, ( char * ) & fileName. src, ( char * ) & fileName. dst) ;
destroy_pool ( pool) ;
return 0 ;
}
copy.c
# include "my_head.h"
void copyfile ( int src, int dst)
{
char buf[ PATHSIZE] ;
int ret;
while ( 1 )
{
ret = read ( src, buf, PATHSIZE) ;
if ( ret == 0 )
{
break ;
}
write ( dst, buf, ret) ;
}
}
void * mytask ( void * arg)
{
int * fd = ( int * ) arg;
copyfile ( fd[ 0 ] , fd[ 1 ] ) ;
}
bool copydir ( thread_pool * pool, char * src, char * dst, struct stat * info)
{
if ( access ( dst, F_OK) )
{
mkdir ( dst, info-> st_mode) ;
}
struct stat * fileinfo = malloc ( sizeof ( struct stat ) ) ;
stat ( dst, fileinfo) ;
if ( ! S_ISDIR ( fileinfo-> st_mode) )
{
printf ( "%s Not a directory!\n" , dst) ;
return false;
}
char current_path[ PATHSIZE] = { 0 } ;
char from_path[ PATHSIZE] = { 0 } ;
char dst_path[ PATHSIZE] = { 0 } ;
getcwd ( current_path, PATHSIZE) ;
chdir ( src) ;
getcwd ( from_path, PATHSIZE) ;
chdir ( current_path) ;
chdir ( dst) ;
getcwd ( dst_path, PATHSIZE) ;
DIR * dp = opendir ( from_path) ;
chdir ( from_path) ;
while ( 1 )
{
struct dirent * ep = readdir ( dp) ;
if ( ep == NULL )
{
printf ( "readdir end!\n" ) ;
break ;
}
if ( strcmp ( ep-> d_name, "." ) == 0 || strcmp ( ep-> d_name, ".." ) == 0 )
continue ;
printf ( "ep->d_name:%s\n" , ep-> d_name) ;
bzero ( fileinfo, sizeof ( struct stat ) ) ;
chdir ( from_path) ;
stat ( ep-> d_name, fileinfo) ;
if ( S_ISREG ( fileinfo-> st_mode) )
{
int * fd = calloc ( 2 , sizeof ( int ) ) ;
fd[ 0 ] = open ( ep-> d_name, O_RDONLY) ;
chdir ( dst_path) ;
fd[ 1 ] = open ( ep-> d_name, O_WRONLY| O_CREAT| O_TRUNC, fileinfo-> st_mode) ;
add_task ( pool, mytask, ( void * ) fd) ;
}
if ( S_ISDIR ( fileinfo-> st_mode) )
{
chdir ( dst_path) ;
mkdir ( ep-> d_name, fileinfo-> st_mode) ;
chdir ( ep-> d_name) ;
char new_path[ PATHSIZE] ;
getcwd ( new_path, PATHSIZE) ;
chdir ( from_path) ;
copydir ( pool, ep-> d_name, new_path, fileinfo) ;
}
}
}
void cal_file_size ( char * src_dir)
{
char srcpath[ PATHSIZE] = { 0 } ;
DIR * dp = opendir ( src_dir) ;
if ( dp == NULL )
{
printf ( "%s opendir() failed" , src_dir) ;
return ;
}
while ( 1 )
{
struct dirent * ep = readdir ( dp) ;
if ( ep == NULL )
{
break ;
}
if ( strncmp ( ep-> d_name, "." , 1 ) == 0 || strcmp ( ep-> d_name, ".." ) == 0 )
continue ;
bzero ( srcpath, PATHSIZE) ;
sprintf ( srcpath, "%s/%s" , src_dir, ep-> d_name) ;
if ( ep-> d_type == DT_DIR)
{
cal_file_size ( srcpath) ;
}
else if ( ep-> d_type == DT_REG)
{
struct stat statBuf;
stat ( srcpath, & statBuf) ;
total_size += statBuf. st_size;
}
}
printf ( "FileSize:%ld\n" , total_size) ;
}
fileture.c
# include "my_head.h"
int filetrue ( char * src_file)
{
struct stat st;
memset ( & st, 0 , sizeof ( st) ) ;
if ( stat ( src_file, & st) == 0 )
{
printf ( "文件存在,可以进行拷贝......\n" ) ;
return 0 ;
}
else
{
perror ( "文件不存在,不可以进行拷贝,即将退出程序.....\n" ) ;
exit ( 0 ) ;
return - 1 ;
}
}
isDir.c
# include "my_head.h"
# include "thread_pool.h"
void Isdir ( struct stat * source_file, struct stat * target_file, thread_pool * pool, char * src_file, char * dst_file)
{
if ( S_ISDIR ( source_file-> st_mode) )
{
printf ( "源文件是目录\t目标文件是目录\n" ) ;
printf ( "开始拷贝目录:%s ----> %s\n" , src_file, dst_file) ;
cal_file_size ( src_file) ;
copydir ( pool, src_file, dst_file, source_file) ;
}
}
isFile.c
# include "my_head.h"
# include "thread_pool.h"
void Isfile ( struct stat * source_file, struct stat * target_file, thread_pool * pool, char * src_file, char * dst_file)
{
if ( S_ISREG ( source_file-> st_mode) && ! S_ISDIR ( target_file-> st_mode) )
{
printf ( "源文件是普通文件\t目标文件不是目录\n" ) ;
printf ( "开始拷贝文件:%s ----> %s\n" , src_file, dst_file) ;
int * fd = calloc ( 2 , sizeof ( int ) ) ;
fd[ 0 ] = open ( src_file, O_RDONLY) ;
if ( fd[ 0 ] == - 1 )
{
perror ( "open fd[0] fail\n" ) ;
}
fd[ 1 ] = open ( dst_file, O_WRONLY| O_CREAT| O_TRUNC, source_file-> st_mode) ;
if ( fd[ 1 ] == - 1 )
{
perror ( "open fd[1] fail\n" ) ;
}
printf ( "FileSIZE:%ld\n" , source_file-> st_size) ;
add_task ( pool, mytask, ( void * ) fd) ;
}
}
isFiletoDir.c
# include "my_head.h"
# include "thread_pool.h"
void IsfileTodir ( struct stat * source_file, struct stat * target_file, thread_pool * pool, char * src_file, char * dst_file)
{
if ( S_ISREG ( source_file-> st_mode) && S_ISDIR ( target_file-> st_mode) )
{
printf ( "源文件是普通文件\t目标文件是目录\n" ) ;
int * fd = calloc ( 2 , sizeof ( int ) ) ;
fd[ 0 ] = open ( src_file, O_RDONLY) ;
if ( fd[ 0 ] == - 1 )
{
perror ( "open fd[0] fail\n" ) ;
}
chdir ( dst_file) ;
fd[ 1 ] = open ( dst_file, O_WRONLY| O_CREAT| O_TRUNC, source_file-> st_mode) ;
if ( fd[ 1 ] == - 1 )
{
perror ( "open fd[1] fail\n" ) ;
}
printf ( "FileSIZE:%ld\n" , source_file-> st_size) ;
add_task ( pool, mytask, ( void * ) fd) ;
}
}
thread_pool.c
# include "thread_pool.h"
void handler ( void * arg)
{
pthread_mutex_unlock ( ( pthread_mutex_t * ) arg) ;
}
void * routine ( void * arg)
{
thread_pool * pool = ( thread_pool * ) arg;
struct task * p;
while ( 1 )
{
pthread_cleanup_push ( handler, ( void * ) & pool-> lock) ;
pthread_mutex_lock ( & pool-> lock) ;
while ( pool-> waiting_tasks == 0 && ! pool-> shutdown)
{
pthread_cond_wait ( & pool-> cond, & pool-> lock) ;
}
if ( pool-> waiting_tasks == 0 && pool-> shutdown == true)
{
pthread_mutex_unlock ( & pool-> lock) ;
pthread_exit ( NULL ) ;
}
p = pool-> task_list-> next;
pool-> task_list-> next = p-> next;
pool-> waiting_tasks-- ;
pthread_mutex_unlock ( & pool-> lock) ;
pthread_cleanup_pop ( 0 ) ;
pthread_setcancelstate ( PTHREAD_CANCEL_DISABLE, NULL ) ;
( p-> do_task) ( p-> arg) ;
pthread_setcancelstate ( PTHREAD_CANCEL_ENABLE, NULL ) ;
free ( p) ;
}
}
bool init_pool ( thread_pool * pool, unsigned int threads_number)
{
pthread_mutex_init ( & pool-> lock, NULL ) ;
pthread_cond_init ( & pool-> cond, NULL ) ;
pool-> shutdown = false;
pool-> task_list = malloc ( sizeof ( struct task ) ) ;
pool-> tids = malloc ( sizeof ( pthread_t ) * MAX_ACTIVE_THREADS) ;
if ( pool-> task_list == NULL || pool-> tids == NULL )
{
perror ( "allocate memory error" ) ;
return false;
}
pool-> task_list-> next = NULL ;
pool-> max_waiting_tasks = MAX_WAITING_TASKS;
pool-> waiting_tasks = 0 ;
pool-> active_threads = threads_number;
int i;
for ( i= 0 ; i< pool-> active_threads; i++ )
{
if ( pthread_create ( & ( ( pool-> tids) [ i] ) , NULL , routine, ( void * ) pool) != 0 )
{
perror ( "create threads error" ) ;
return false;
}
}
return true;
}
bool add_task ( thread_pool * pool, void * ( * do_task) ( void * arg) , void * arg)
{
struct task * new_task = malloc ( sizeof ( struct task ) ) ;
if ( new_task == NULL )
{
perror ( "allocate memory error" ) ;
return false;
}
new_task-> do_task = do_task;
new_task-> arg = arg;
new_task-> next = NULL ;
pthread_mutex_lock ( & pool-> lock) ;
if ( pool-> waiting_tasks >= MAX_WAITING_TASKS)
{
pthread_mutex_unlock ( & pool-> lock) ;
fprintf ( stderr , "too many tasks.\n" ) ;
free ( new_task) ;
return false;
}
struct task * tmp = pool-> task_list;
while ( tmp-> next != NULL )
tmp = tmp-> next;
tmp-> next = new_task;
pool-> waiting_tasks++ ;
pthread_mutex_unlock ( & pool-> lock) ;
pthread_cond_signal ( & pool-> cond) ;
return true;
}
int add_thread ( thread_pool * pool, unsigned additional_threads)
{
if ( additional_threads == 0 )
return 0 ;
unsigned total_threads = pool-> active_threads + additional_threads;
int i, actual_increment = 0 ;
for ( i = pool-> active_threads; i < total_threads && i < MAX_ACTIVE_THREADS; i++ )
{
if ( pthread_create ( & ( ( pool-> tids) [ i] ) , NULL , routine, ( void * ) pool) != 0 )
{
perror ( "add threads error" ) ;
if ( actual_increment == 0 )
return - 1 ;
break ;
}
actual_increment++ ;
}
pool-> active_threads += actual_increment;
return actual_increment;
}
int remove_thread ( thread_pool * pool, unsigned int removing_threads)
{
if ( removing_threads == 0 )
return pool-> active_threads;
int remaining_threads = pool-> active_threads - removing_threads;
remaining_threads = remaining_threads > 0 ? remaining_threads : 1 ;
int i;
for ( i= pool-> active_threads- 1 ; i> remaining_threads- 1 ; i-- )
{
errno = pthread_cancel ( pool-> tids[ i] ) ;
if ( errno != 0 )
break ;
}
if ( i == pool-> active_threads- 1 )
return - 1 ;
else
{
pool-> active_threads = i+ 1 ;
return i+ 1 ;
}
}
bool destroy_pool ( thread_pool * pool)
{
printf ( "......\n" ) ;
printf ( "完成拷贝!\n" ) ;
pool-> shutdown = true;
pthread_cond_broadcast ( & pool-> cond) ;
int i;
for ( i= 0 ; i< pool-> active_threads; i++ )
{
errno = pthread_join ( pool-> tids[ i] , NULL ) ;
if ( errno != 0 )
{
printf ( "join tids[%d] error: %s\n" , i, strerror ( errno) ) ;
}
}
free ( pool-> task_list) ;
free ( pool-> tids) ;
free ( pool) ;
return true;
}
Makefile
CC= gcc
TARGET = . / bin/ copy
C_SOURCE= $( wildcard . / src