本blog主要是模仿Linux的cp命令的功能,未实现参数,只是基础功能部分。

本文的主要目的在于练习 文件流目录流 中的函数的使用。

主要功能包括两种:

  • 源文件属性为文件,拷贝到其它文件(内容复制)或目录(作为目录子文件)
  • 源文件属性为目录,拷贝到其它目录(作为子目录存在)

其实现的流程图如下所示:

本copy我们通过三个文件来实现:

  • main.c:流程的实现
  • copy.c:拷贝功能的实现
  • copy.h:必要的头文件
  1. 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;
    }
  2. 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;
    }
  3. 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" 代码实现简介的更多相关文章

  1. linux 命令cp拷贝

    linux复制指定目录下的全部文件到另一个目录中复制指定目录下的全部文件到另一个目录中文件及目录的复制是经常要用到的.linux下进行复制的命令为cp.假设复制源目录 为 dir1 ,目标目录为dir ...

  2. Linux命令——cp、rm、mv、touch、file、dir

    cp copy 拷贝文件 拷贝过程不指定目标文件名 则目标文件名和源文件名一样 [root@WebServer ~]# cp /91xueit/teacher.txt 51cto/ 拷贝过程指定目标文 ...

  3. linux命令-cp/scp {拷贝}

    一 命令解释 名称:cp 使用权限:所有使用者 使用方式: cp [options] source dest cp [options] source... directory 命令参数: -a 尽可能 ...

  4. Linux命令-cp

    cp命令用于复制文件到目录 参数 -r 递归持续复制(用于目录) 参数 -p 保留原始文件属性 参数 -d 若对象为链接文件,保留该链接文件的属性 参数 -a 相当于以上三者之和(-pdr) [roo ...

  5. Linux 命令 - cp: 拷贝文件和目录

    命令格式 cp [OPTION]... [-T] SOURCE DEST cp [OPTION]... SOURCE... DIRECTORY cp [OPTION]... -t DIRECTORY ...

  6. linux命令--cp、tail、cd、mv、history、cd

    day1 cd命令 cd ../定位至上级目录 cd ./定位到当前目录 cd ~ 定位当前用户目录 cd / 定位系统根目录 cd - 返回进入此目录之前所在的目录 day2 mv命令: mv时,若 ...

  7. linux命令 cp 递归复制 带权限复制

    cp -r 递归复制源目录下所有文件及子目录 到 目标目录或文件 cp -p 把源文件或目录下的所具有的权限一同复制 到 目标目录或文件

  8. linux 命令cp -a的用法

    cp -a 保留原文件属性的前提下复制文件 cp -r dirname(源文件) destdi(目标文件) 复制目录后其文件属性会发生变化想要使得复制之后的目录和原目录完全一样包括文件权限,可以使用c ...

  9. 核心系统命令实战 第一章Linux命令行简介

    第一章Linux命令行简介 1.1 Linux命令行概述 1.1.1 Linux 命令行的开启和退出 开启:登陆账号密码进入系统 退出:exit/logout  快捷键:Ctrl+d 1.1.2 Li ...

随机推荐

  1. WebAPI的AuthorizeAttribute扩展类中获取POST提交的数据

    在WEBAPI中,AuthorizeAttribute类重写时,如何获取post数据是个难题,网上找资料也不好使,只能自己研究,通过研究发现,WEBAPI给了我们获取POST数据的可能,下面介绍一下: ...

  2. max渲染通道元素的范例

    renderElementManager = MaxOps.GetCurRenderElementMgr() renderElementManager.Removeallrenderelements( ...

  3. JVM伪共享

    CPU缓存中的cache line缓存行是缓存的最小单位,同一个时刻内只允许一个cpu内核进行操作.一般,缓存行的大小为64字节,这样的大小可以存放多个java对象的对象头.因此,当两个不同的线程同时 ...

  4. ovs 源mac, 目的src 互换

    push:NXM_OF_ETH_SRC[],push:NXM_OF_ETH_DST[],pop:NXM_OF_ETH_SRC[],pop:NXM_OF_ETH_DST[] 1:把src mac推到栈顶 ...

  5. Datetimepicker.js用法

    $('.form_date').datetimepicker({//初始化 language: 'zh-CN', //weekStart: 1, //todayBtn: 1, autoclose: 1 ...

  6. gdb的调试常用命令

    一.gdb常用的命令 list                       l    常看源代码 break                  b    设置断点     b  10(行号)    b ...

  7. CentOS 7 - 安装Eclipse

    注意问题:Eclipse官方网站提供的tar文件有可能有问题,我今天下载的一个tar文件,在Windows下解压缩,随后放到CentOS 7里面不行,随后我又重新下载一份,还是不行,最终我下载了另外一 ...

  8. 768. Max Chunks To Make Sorted II

    This question is the same as "Max Chunks to Make Sorted" except the integers of the given ...

  9. 洛谷P3369 【模板】普通平衡树(Splay)

    题面 传送门 题解 鉴于最近的码力实在是弱到了一个境界--回来重新打一下Splay的板子--竟然整整调了一个上午-- //minamoto #include<bits/stdc++.h> ...

  10. 如何实现keep-alive

    路径: 由上图可知,keep-alive.js导出的对象(如下),作为一个属性将会注入到Vue.options.components中. const patternTypes = [String, R ...