C语言实现简单版Linux的cp命令

C语言实现简单版的Linux的cp命令

前言:

​ 这是我的第一篇CSDN文章,写的不够好的地方有请各路大神指正。本人也是接触代码时间很短,在这里希望把自己学习到的知识写成一些有用的代码。后面有空的话还会继续多写写这类的文章。

​ 不想看文章写了啥的同鞋请直接拉到最下面拉代码。

一、通过主函数传参实现cp命令参数的传入

(1)int argc

​ 这个参数记录着有多少个主函数传参,数值为实际需要的传参数加1而cp命令需要两个参数(不考虑-r -f等等参数),分别是复制的源路径以及复制的目标路径,所以用判断是否输入了足够的参数。

(2)char ** argv

​ 这个二级指针则是字符串数组,可以写成char * argv[]。从argv[1]开始是第一个传参,argv[2]是第二个传参。。。而argv[0]是执行文件的名字。

二、通过open函数打开对应路径,判断该路径是普通文件还是目录文件

​ 对应函数:get_cp_status(const char * path , int flag);

​ 函数里面利用open函数打开path,如果打开失败,则判断errno错误码,当errno等于EISDIR时,是目录,返回0,如果不是则perror输出错误提示,并返回-1。如果打开成功,返回打开成功的文件描述符

​ flag是打开文件的权限,对应有三个宏定义:FILE_RDWR(可读可写),FILE_CREATE(不存在则创建),FILE_TUNC(存在则清空),当多个参数需要使用的时候用+连接。

对argv[1]和argv[2]都进行判断并打开,并获得返回值Path1_fd,Path2_fd作后面区分以及复制使用。

三、根据Path1_fd,Path2_fd判断复制方式并进行复制

(1)Path1_fd,Path2_fd均大于0

​ 对应函数:fn_Cp_File_to_File(int fd1 , int fd2);

​ 证明两个主函数传参都是文件的路径。那么此时Path1_fd,Path2_fd均是文件描述符,只需要使用read函数读Path1_fd,然后把读到的内容放在buf里面,然后用write函数往Path2_fd里面写buf的内容即可。

(2)Path1_fd大于0 ,Path2_fd等于0

​ 对应函数:fn_Cp_File_to_Dir(const char * file_path ,const char * dir_path);

​ 此时Path1_fd是文件,Path2_fd是目录,把文件复制到指定目录中。该函数的传参1是需要复制的文件路径,传参2是目录路径,他们可以是我们的两个主函数传参。

​ 这时候需要在 Path2对应的目录中创建一个新的,与Path1文件名相同的文件并且打开获取其文件描述符,此时需要用到open函数,mode传参需要设置成O_RDWR | O_CREAT | O_TRUNC,可读可写,不存在则创建(对应在path2目录中没有这个文件),存在则清空(对应在path2目录中已经存在这个文件)。

​ 由于path1是一个路径,则编写函数get_name把path1中的文件名提取出来。主要思路就是用strtok库函数对path1路径根据”/”进行切割。每次切割的字符串保存在堆空间中,当strtok函数返回值为NULL,此时堆空间的字符串就是path1的文件名。

​ 最后重新根据path1文件的路径用open函数重新打开复制源文件,配合已经创建好的,而且在path2里面的,一个待复制的文件,使用fn_Cp_File_to_File函数复制。

(3)Path1_fd,Path2_fd均等于0

​ 对应函数:fn_Cp_Dir_to_Dir(const char * dir_path1 ,const char * dir_path2);

​ 代表此时的复制是把一个目录复制到另外一个目录中去。(难点)

1.获得当前工作路径:

​ 当主函数传参为相对路径的时候(不以”/”, ”~” 开头的路径),获取源文件夹以及目标文件夹的源路径的时候需要先切换回当前工作路径,在进入下一个路径。

2.获得源文件夹以及目标文件夹的绝对路径

​ 当路径为绝对路径时,传参路径就是文件夹的路径。当为相对路径的时候,需要进入该路径,然后使用getcwd函数获得文件夹的绝对路径。

3.在目标文件夹里面创建对应的目录

​ 使用前面的get_name函数获得path1路径文件夹的名字,在path2路径下创建使用mkdir函数对应文件夹。并且使用sprintf函数把目标文件夹绝对路径和目录名拼接起来。

使用readdir函数读取源文件夹的文件名,当读到非目录的时候:把源文件夹绝对路径与该文件名拼接。此时就可以调用前面写好的fn_Cp_File_to_Dir函数把文件复制到指定目录中。

当读到的是一个目录的时候,使用sprintf函数把该目录名与目标文件夹路径拼接起来,以及用sprintf函数把该目录名与源目标文件夹路径拼接起来。这两个路径作为fn_Cp_Dir_to_Dir函数传参,递归调用本函数继续进行复制。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>

#define FILE_RDWR 1
#define FILE_CREATE 2
#define FILE_TUNC 4

static int get_cp_status(const char * path , int flag);
static void fn_Cp_File_to_File(int fd1 , int fd2);
static void fn_Cp_File_to_Dir(const char * file_path ,const char * dir_path);
static void fn_Cp_Dir_to_Dir(const char * dir_path1 ,const char * dir_path2);
static char * get_name(const char * path);

int main(int argc , char **argv)
{
    int Path1_fd;
    int Path2_fd;
    if(argc < 3)
    {
        printf("请输入足够的参数\n");
        return 0;
    }

    //判断传参路径是什么文件,普通文件则打开,目录文件返回0,返回值是文件描述符
    Path1_fd = get_cp_status(argv[1] , FILE_RDWR);
    Path2_fd = get_cp_status(argv[2] , FILE_RDWR + FILE_CREATE + FILE_TUNC);

    //打开文件出错
    if(Path1_fd < 0 || Path2_fd < 0)
    {
        return 0;
    }

    //文件间复制
    if(Path1_fd > 0 && Path2_fd > 0)
    {
        fn_Cp_File_to_File(Path1_fd , Path2_fd);
        close(Path1_fd);
        close(Path2_fd);
    }
    
    //文件到目录复制
    if(Path1_fd > 0 && Path2_fd == 0)
    {
        close(Path1_fd);
        fn_Cp_File_to_Dir(argv[1] , argv[2]);
    }
    
    //目录到目录复制
    if(Path1_fd == 0 && Path2_fd == 0)
    {
        fn_Cp_Dir_to_Dir(argv[1] , argv[2]);
    }

    return 0;
}

//返回值:0(路径为目录) , 返回值大于0(路径为文件) , 返回-1:打开文件失败
static int get_cp_status(const char * path , int flag)
{
    int fd = -1;

    if(flag == 7)
    {
        fd = open(path , O_RDWR | O_CREAT | O_TRUNC);
    }
    else
    {
        fd = open(path , O_RDWR);
    }
    
    if(fd <= 0)
    {
        if(errno == EISDIR)
        {
            return 0;
        }
        else
        {
            perror("错误原因");
            return -1;
        }
    }
    else
    {
        return fd;
    }
}

static void fn_Cp_File_to_File(int fd1 , int fd2)
{
    char tmp_buf[1024] = {0};
    while(1)
    {
        int ret = read(fd1 , tmp_buf , 1024);
        if(ret <= 0)
        {
            break;
        }
        write(fd2 , tmp_buf , ret);
    }
}

static char * get_name(const char * path)
{
    char tmp_path[1024] = {0};
    char * tmp_p = malloc(1024);
    char * p = NULL;
    
    //字符串处理
    strcpy(tmp_path , path);
    p = strtok(tmp_path , "/");
    strcpy(tmp_p , p);
    while(1)
    {
        p = strtok(NULL , "/");
        if(p == NULL)
        {
            break;
        }
        else
        {
            strcpy(tmp_p , p);
        }
    }
    
    return tmp_p;
}

static void fn_Cp_File_to_Dir(const char * file_path ,const char * dir_path)
{
    char cp_path[1024] = {0};
    int file1_fd = 0;
    int file2_fd = 0;
    file1_fd = open(file_path , O_RDWR);

    //获得目标文件夹路径
    chdir(dir_path);
    getcwd(cp_path , 1024);
    sprintf(cp_path , "%s/%s" , cp_path , get_name(file_path));
    
    file2_fd = open(cp_path , O_RDWR | O_CREAT | O_TRUNC);
    fn_Cp_File_to_File(file1_fd , file2_fd);

    close(file1_fd);
    close(file2_fd);
}

static void fn_Cp_Dir_to_Dir(const char * dir_path1 ,const char * dir_path2)
{
    DIR * dp = NULL;
    struct dirent * dir_info;
    char cp_path_begin[1024] = {0};
    char cp_path_from[1024] = {0};
    char cp_path_to[1024] = {0};

    getcwd(cp_path_begin , 1024);

    //获得完整的路径1
    if(dir_path1[0] == '~' || dir_path1[0] == '/')
    {
        strcpy(cp_path_from , dir_path1);
        printf("cp_path from:%s\n" , cp_path_from);
    }
    else
    {
        chdir(dir_path1);
        getcwd(cp_path_from , 1024);
        chdir(cp_path_begin);
        printf("cp_path from:%s\n" , cp_path_from);
    }

    //获得完整的路径2
    if(dir_path2[0] == '~' || dir_path2[0] == '/')
    {
        strcpy(cp_path_to , dir_path2);
        printf("cp_path to:%s\n" , cp_path_to);
        mkdir(cp_path_to , 0777);
    }
    else
    {
        chdir(dir_path2);
        getcwd(cp_path_to , 1024);
        chdir(cp_path_begin);
        //创建被复制的目录
        sprintf(cp_path_to , "%s/%s" , cp_path_to , get_name(dir_path1));
        printf("cp_path to:%s\n" , cp_path_to);
        mkdir(cp_path_to , 0777);
    }

    //开始复制
    dp = opendir(cp_path_from);
    while(1)
    {
        dir_info = readdir(dp);
        if(dir_info == NULL)
        {
            break;
        }
        if(dir_info->d_type == DT_DIR)
        {
            //排除.和..
            if((strcmp(dir_info->d_name , ".") == 0) || (strcmp(dir_info->d_name , "..") == 0))
            { 
                continue;
            }
            //重新拼接目录
            char cp_path_from_r[1024] = {0};
            char cp_path_to_r[1024] = {0};
            sprintf(cp_path_from_r , "%s/%s" , cp_path_from , dir_info->d_name);
            sprintf(cp_path_to_r , "%s/%s" , cp_path_to , dir_info->d_name);
            fn_Cp_Dir_to_Dir(cp_path_from_r , cp_path_to_r);
        }
        else
        {
            char file_path[1024] = {0};
            sprintf(file_path , "%s/%s" , cp_path_from , dir_info->d_name);
            fn_Cp_File_to_Dir(file_path , cp_path_to);
        }
    }
    closedir(dp);
    return;
}
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: cp命令Linux系统中常用的命令之一,用于复制文件或目录。要用C语言实现cp命令,需要使用系统调用函数来完成文件的读写操作。具体实现步骤如下: 1. 打开源文件和目标文件,使用open()函数,获取文件描述符。 2. 读取源文件的内容,使用read()函数,将读取的内容存储到缓冲区中。 3. 将缓冲区中的内容写入目标文件,使用write()函数。 4. 关闭源文件和目标文件,使用close()函数,释放文件描述符。 5. 处理错误情况,如文件打开失败、读写失败等。 需要注意的是,如果要复制目录,则需要使用递归函数来遍历目录中的所有文件和子目录,并逐一复制。同时,还需要处理文件权限、时间戳等信息的复制。 ### 回答2: 在Linux系统中,cp命令的作用是将一个文件复制到另一个文件或目录。一般情况下,我们使用cp命令来进行文件的备份或复制,而在Linux系统中,cp命令实现是基于C语言的。以下是用C语言实现cp命令的方法: 在C语言中,可以使用文件操作函数来实现cp命令。文件操作函数主要有fopen、fclose、fread、fwrite、fgetc等函数,它们可以实现对文件的读和写。 首先,我们需要打开源文件和目标文件,使用fopen函数可以打开文件并返回文件指针,然后使用fread和fwrite函数来读取和写入文件。可以使用fgetc函数来逐步读取一个文件中的字符,并使用fwrite函数来逐个写入目标文件中。注意,在写入目标文件之前,我们需要先创建目标文件,可以使用fopen函数来创建目标文件并返回文件指针。 在实现cp命令时,必须要判断文件复制是否成功。可以使用feof函数来检查文件是否读取到了文件末尾,如果文件读取到了文件末尾,则表示文件已经读取完毕。可以使用ferror函数来检查是否有错误发生,例如文件不存在或无法读取文件等错误。 最后,完成文件复制后,我们需要关闭源文件和目标文件。可以使用fclose函数关闭文件并释放文件指针,以确保程序的执行效率和数据安全。 总之,用C语言实现cp命令需要掌握文件操作函数的使用,能够编写出安全、高效、可靠的文件复制程序。 ### 回答3: CP命令Linux系统的常用命令之一,它用于复制文件或目录。在Linux系统中,可以使用C语言实现CP命令。下面是一些关于如何使用C语言实现CP命令的基本步骤: 1. 引入必要的头文件 为了实现CP命令,需要引入一些必要的头文件,如<stdio.h>、<stdlib.h>、<unistd.h>、<string.h>等。这些头文件包含了一些常用的函数和操作系统相关的宏定义。 2. 获取源文件名和目标文件名 从命令行参数中获取源文件和目标文件名。一般来说,CP命令命令行参数有两个,第一个是源文件名,第二个是目标文件名。可以使用argc和argv[]来获取这些参数。 3. 打开源文件和目标文件 使用系统调用函数open()来打开源文件和目标文件。打开源文件时,需要使用只读模式,而打开目标文件时,需要使用写模式。如果目标文件已经存在,则需要进行覆盖处理。 4. 读取源文件内容并写入目标文件中 使用系统调用函数read()和write()来读取源文件的内容并写入到目标文件中。在读取和写入时,需要注意缓冲区的大小和残留部分的处理。 5. 关闭文件指针 在使用完文件后,需要使用系统调用函数close()来关闭文件指针。这个步骤非常重要,在使用完文件后,必须关闭文件以便释放系统资源。 以上就是使用C语言实现CP命令的基本步骤。当然,CP命令还有一些其他的功能,如递归拷贝目录、保留文件属性等,这些功能可以通过使用其他系统调用函数和自定义函数来实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值