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
Linux 命令 "cp" 代码实现简介的更多相关文章
- linux 命令cp拷贝
linux复制指定目录下的全部文件到另一个目录中复制指定目录下的全部文件到另一个目录中文件及目录的复制是经常要用到的.linux下进行复制的命令为cp.假设复制源目录 为 dir1 ,目标目录为dir ...
- Linux命令——cp、rm、mv、touch、file、dir
cp copy 拷贝文件 拷贝过程不指定目标文件名 则目标文件名和源文件名一样 [root@WebServer ~]# cp /91xueit/teacher.txt 51cto/ 拷贝过程指定目标文 ...
- linux命令-cp/scp {拷贝}
一 命令解释 名称:cp 使用权限:所有使用者 使用方式: cp [options] source dest cp [options] source... directory 命令参数: -a 尽可能 ...
- Linux命令-cp
cp命令用于复制文件到目录 参数 -r 递归持续复制(用于目录) 参数 -p 保留原始文件属性 参数 -d 若对象为链接文件,保留该链接文件的属性 参数 -a 相当于以上三者之和(-pdr) [roo ...
- Linux 命令 - cp: 拷贝文件和目录
命令格式 cp [OPTION]... [-T] SOURCE DEST cp [OPTION]... SOURCE... DIRECTORY cp [OPTION]... -t DIRECTORY ...
- linux命令--cp、tail、cd、mv、history、cd
day1 cd命令 cd ../定位至上级目录 cd ./定位到当前目录 cd ~ 定位当前用户目录 cd / 定位系统根目录 cd - 返回进入此目录之前所在的目录 day2 mv命令: mv时,若 ...
- linux命令 cp 递归复制 带权限复制
cp -r 递归复制源目录下所有文件及子目录 到 目标目录或文件 cp -p 把源文件或目录下的所具有的权限一同复制 到 目标目录或文件
- linux 命令cp -a的用法
cp -a 保留原文件属性的前提下复制文件 cp -r dirname(源文件) destdi(目标文件) 复制目录后其文件属性会发生变化想要使得复制之后的目录和原目录完全一样包括文件权限,可以使用c ...
- 核心系统命令实战 第一章Linux命令行简介
第一章Linux命令行简介 1.1 Linux命令行概述 1.1.1 Linux 命令行的开启和退出 开启:登陆账号密码进入系统 退出:exit/logout 快捷键:Ctrl+d 1.1.2 Li ...
随机推荐
- 设计模式之单件模式(Singleton Pattern)
一.单件模式是什么? 单件模式也被称为单例模式,它的作用说白了就是为了确保“该类的实例只有一个” 单件模式经常被用来管理资源敏感的对象,比如:数据库连接对象.注册表对象.线程池对象等等,这种对象如果同 ...
- INNER JOIN与LEFT JOIN在SQL Server的性能
我创建了INNER JOIN 9桌,反正需要很长的(超过五分钟).所以,我的民歌改变INNER JOIN来LEFT JOIN LEFT JOIN的性能较好,在首次尽管我所知道的.之后我变了,查询的速度 ...
- NetCore入门篇:(七)Net Core项目使用Controller之二
一.简介 1.说明Post,Get定义的区别. 2.说明如何路由定义. 二.Get.Post定义 1.api不定义访问方式时,同时支持get 和 post.如果定义某种方式,则仅支持某种方式.具体看代 ...
- 第二章 ConcurrentHashMap源码解析
注:在看这篇文章之前,如果对HashMap的层不清楚的话,建议先去看看HashMap源码解析. http://www.cnblogs.com/java-zhao/p/5106189.html 1.对于 ...
- Open vSwitch 2.9.2 创建 RPM 安装包
1.安装依赖环境 yum install gcc make python-devel openssl-devel graphviz autoconf automake rpm-build redhat ...
- jzoj2941
我們可以暴力枚舉每一個人分幾個糖果,再暴力統計答案即可 每次遞歸下去可以從1-n號人,決定選多少個糖果再遞歸 #include<bits/stdc++.h> using namespace ...
- 七,apache配置域名
配置域名服务器流程: (1)在httpd.conf中启用虚拟主机,Include conf/extra/httpd-vhosts.conf前面的#去掉. (2)在httpd.conf中修改项目路径为自 ...
- Flask从入门到精通之大型程序的结构二
一.程序包 程序包用来保存程序的所有代码.模板和静态文件.我们可以把这个包直接称为app(应用),如果有需求,也可使用一个程序专用名字.templates 和static 文件夹是程序包的一部分,因此 ...
- numpy的ravel()和flatten()函数比较
功能 两个函数的功能都是将多维数组降为一维. 用法 import numpy as np arr = np.array([[1, 2],[3, 4]]) arr.flatten() arr.ravel ...
- 理解HashMap的原理
HashMap内部数据结构 HashMap内部采用数组和链表结合的方式来存取数据(见下图).这种方式有什么好处呢? 我们知道,数组操作对于检索是O(1)的,能够很快的根据数组的下标定位对 ...