Linux 命令 "cp" 代码实现简介
本blog主要是模仿Linux的cp命令的功能,未实现参数,只是基础功能部分。
本文的主要目的在于练习 文件流 和 目录流 中的函数的使用。
主要功能包括两种:
- 源文件属性为文件,拷贝到其它文件(内容复制)或目录(作为目录子文件)
- 源文件属性为目录,拷贝到其它目录(作为子目录存在)
其实现的流程图如下所示:

本copy我们通过三个文件来实现:
- main.c:流程的实现
- copy.c:拷贝功能的实现
- copy.h:必要的头文件
-
main.c
/*********************************************************
* File name:
* Description:
* Author: Jimmy_Nie
* Version Modify Time
* v1.0 creat 2017-09-12
*
*********************************************************/include "copy_file.h"
int main(int argc, char *argv[])
{
//Check the arguments
if( 3 != argc)
{
printf("%s(%d): arguments error!\n",FILE, LINE);
exit(EXIT_FAILURE);
}//check the source file is a file or a directory
struct stat src_stat;//destination file check
struct stat dest_stat;//If source is a file
if( FILES == check_file(argv[1], &src_stat) )
{
FILE_ENUM dest_enum;
dest_enum = check_file( argv[2], &dest_stat );char cmd[100] = "";
char ch;switch(dest_enum)
{
case NOT_EXIST:
sprintf(cmd, "touch %s", argv[2]);
system( cmd );check_file( argv[2], &dest_stat );
cp_file(argv[1], argv[2], &dest_stat);break;
case DIRECTORY:
cp_file(argv[1], argv[2], &dest_stat);
break;case FILES:
fprintf(stdout, "Overwrite the dest file %s, [y/n]\n", argv[2]);
ch = getchar();if( ch == 'Y' || ch == 'y' )
{
cp_file(argv[1], argv[2], &dest_stat);
}
else
exit(0);break;
default:
fprintf(stderr, "%s(%d): file type error\n", FILE, LINE);
}
}//If source file is a directory
else if( DIRECTORY == check_file(argv[1], &dest_stat) )
{
FILE_ENUM dest_enum;
dest_enum = check_file( argv[2], &dest_stat );char cmd[100] = "";
switch(dest_enum)
{
case NOT_EXIST:
sprintf(cmd, "mkdir -p %s", argv[2]);
system( cmd );
cp_dir(argv[1], argv[2] );
break;case DIRECTORY:
cp_dir(argv[1], argv[2]);
break;case FILES:
fprintf(stderr, "Can't copy a directory to a file\n");
exit(EXIT_FAILURE);
break;default:
fprintf(stderr, "%s(%d): file type error\n", FILE, LINE);
break;
}
}return 0;
} -
copy.c
include "copy_file.h"
FILE_ENUM check_file(char *var, struct stat *st)
{
if( stat(var, st) ) //if stat function error(renturn nonzero)
{
if( ENOENT == errno) //No such file or directory
{
return NOT_EXIST;
}
else
{
perror("stat");
exit(EXIT_FAILURE);
}
}else // stat() ok, no error
{
//check file attr(dir or file)
if( S_ISDIR(st->st_mode ))
return DIRECTORY;
else if( S_ISREG(st->st_mode) )
return FILES;
else
{
fprintf(stderr, "%s(%d):file type error", FILE , LINE);
exit(EXIT_FAILURE);
}
}
}//-----------------------------------------------------
int cp_file(char *src_var, char *dest_var, struct stat *st)
{
FILE *src = NULL;
FILE *dest = NULL;if( S_ISREG(st->st_mode) ) //if dest is file
{
//1. open src and dest file
if( NULL == (src = fopen(src_var, "r")) )
{
perror("fopen");
exit(EXIT_FAILURE);
}if( NULL == (dest = fopen(dest_var, "w+")) )
{
perror("fopen");
exit(EXIT_FAILURE);
}//2. copy the context from src to dest
char buf[1024];
int num;while(1)
{
// if at the end of file or an error occured
if( 1024 != (num = fread(buf, 1,1024, src)))
{
if( !feof(src))
{
perror("fread");
exit(EXIT_FAILURE);
}else
{
fwrite(buf, 1, num, dest);
fclose(dest); //3. close dest file
break;
}
}
fwrite(buf, 1, 1024, dest);}
//3. close src file
fclose(src);
return 0;
}if( S_ISDIR(st->st_mode) )
{
char buf[100]="";//make the relative path to absolute path
strncpy(buf, dest_var, sizeof(dest_var));
strcat(buf, src_var);//if dest file doesn't exist, creat it first
char cmd[100]="";
sprintf(cmd, "touch %s",buf);
system(cmd);struct stat new_dest_stat;
if( stat(buf, &new_dest_stat))
{
perror("stat");
exit(EXIT_FAILURE);
}cp_file(src_var, buf, &new_dest_stat);
}return 0;
}//----------------------------------------------
//if src file is a dir
int cp_dir(char *src, char *dest)
{
DIR *dirp = NULL;//1. open the dir
if( NULL == (dirp = opendir(src)) )
{
perror("opendir");
exit(EXIT_FAILURE);
}struct dirent *entp = NULL;
//2. read the dir
while( NULL != (entp = readdir(dirp))) //read the dir context
{
if( 0 == (strcmp(entp->d_name,"..")) || 0 == (strcmp(entp->d_name, ".")))
{
continue;
}char src_buf[100] = "";
char dest_buf[100] = "";sprintf(src_buf, "%s/%s\0", src, entp->d_name);
sprintf(dest_buf, "%s/%s\0", dest, entp->d_name);struct stat src_stat;
if( stat(src_buf,&src_stat) )
{
perror("stat");
exit(EXIT_FAILURE);
}if( S_ISREG(src_stat.st_mode) )
{
cp_file(src_buf, dest_buf, &src_stat);
}else if( S_ISDIR(src_stat.st_mode) )
{
if( -1 == mkdir(dest_buf, src_stat.st_mode) )
{
perror("mkdir");
exit(EXIT_FAILURE);
}cp_dir(src_buf, dest_buf); //if subdir, recursive call itself
}
}return 0;
} -
copy.h
ifndef COPY_H
define COPY_H
include <stdio.h>
include <unistd.h>
include <sys/types.h>
include <sys/stat.h>
include <errno.h>
include <string.h>
include <dirent.h>
include <stdlib.h>
typedef enum
{
NOT_EXIST=1,
DIRECTORY,
FILES
}FILE_ENUM;extern FILE_ENUM check_file(char *var, struct stat *st); //检查文件类型
extern int cp_file(char *src_var, char *dest_var, struct stat *st); //copy文件
extern int cp_dir(char *src, char *dest); //copy目录
endif

浙公网安备 33010602011771号