cp指令_cp-fd命令

参数
- 源文件:指定源文件列表。默认情况下,cp命令不能复制目录,如果要复制目录,则需要加 [-R] 选项。
- 目标文件:指定目标文件。当源文件为多个时,要求指定 “目标文件” 为目录。

实例

如果把一个文件复制到目标文件中,而目标文件已经存在。那么该目标文件的内容将被清空。此命令中的路径参数既可以是绝对路径,也可以是相对路径。通常会用到 ‘.’ 或 ‘…’ 的形式,例如下面的命令是将指定文件复制到当前目录下。

cp ../code/mycp.c ./

如果没有文件的复相关权限,则命令会报错。
将 test1 复制到 /home/jelly 目录下并改名为 test2:

cp test1 /home/jelly/test2

我们在 linux 下复制文件的时候,有时候会覆盖同名文件,此时会有选项 [Y/n] 让我们选择是否需要覆盖对应文件。

cp命令执行拓扑图

这里写图片描述

命令核心代码

cp命令的核心点之一是拷贝目录文件。对目录文件的拷贝,实际上是对该目录下的所有文件的拷贝。显然,这是一个递归的过程。

我们循环读取目录下的每个文件,对于 ‘.’ 和 ‘…’ 不做任何处理,将读到的其它文件作为新的源文件(记得要拼接新的源文件路径),然后针对该文件的类型,选择调用 “cp_file” 或者 “cp_dir”。实际上,linux下的文件类型有7种,我们应该对于每种类型,都实现一个拷贝函数,但此处仅仅是一个简洁版本,所以只处理目录文件和普通文件两种。

首先介绍读目录相关的接口:

DIR *opendir(const char *name);
功能:打开一个目录;
参数:目录的路径;
返回值:若打开成功返回一个指向文件流的指针,用户可以通过该指针访问目录下的文件,若打开失败,则返回 NULL;
说明:一般情况下打开失败的原因包括:
 1) 路径为空或者路径非法;
 2) 进程可打开的文件描述符数量达到上限;
 3) 系统可打开的文件描述符达到上限.
struct dirent \*readdir(DIR \*dirp);
功能:读取目录的内容; 
参数:指向文件流的指针;
返回值:若 执行成功,返回指向文件文件结构体(结构体内容如下)的指针,若读到目录结尾,则返回 NULL。   

下面是拷贝目录的代码:

int cp_dir(const char *src, const char *dst, mode_t mode){
    LOG("copy dir: '%s' to '%s'\n", src, dst);
    if(src == NULL || dst == NULL){
        return -1;
    }
    (void)mode;
    DIR *fd_dst = opendir(src);
    struct dirent *fd_read = NULL;
    while((fd_read=readdir(fd_dst)) != NULL) {
        if(fd_read->d_name[0] == '.'){
            continue;
        }

        char *path_src = (char*)malloc(strlen(src)+strlen(fd_read->d_name)+1);
        sprintf(path_src, "%s/%s", src, fd_read->d_name);
        char *path_dst = (char*)malloc(strlen(dst)+strlen(fd_read->d_name)+1);
        sprintf(path_dst, "%s/%s", dst, fd_read->d_name);
        struct stat sbuf;
        memset(&sbuf, 0x00, sizeof(sbuf));
        if(stat(path_src, &sbuf) == -1){
            LOG("file stat error!\n");
        }
        if(S_ISREG(sbuf.st_mode)){//源是文件
            cp_file(path_src, path_dst, sbuf.st_mode);
        }else if(S_ISDIR(sbuf.st_mode)){//源是目录
            mkdir(path_dst, sbuf.st_mode);
            cp_dir(path_src, path_dst, sbuf.st_mode);
        }
        free(path_src);
        free(path_dst);
    }
    return 0;
}

文件的拷贝实际上是将源文件内容读出来,然后写到目标文件中,具体代码如下:

int cp_file(const char *src, const char *dst, mode_t mode){
    LOG("copy file: '%s' to '%s'\n", src, dst);
    if(src == NULL || dst == NULL){
        return -1;
    }
    int fd_src = open(src, O_RDONLY);
    if(fd_src == -1){
        LOG("open src file error: %s\n", src);
    }
    int fd_dst = open(dst, O_WRONLY | O_CREAT, mode);
    if(fd_dst == -1){
        LOG("open dst file error: %s\n", dst);
    }
    char buff[1024] = {0};
    ssize_t size = 0;
    int totol_size = 0;
    while((size = read(fd_src, buff, 1023)) > 0){
        totol_size += size;
        buff[size] = '\0';
        write(fd_dst, buff, size);
        memset(buff, 0x00, 1024);
    }
    return totol_size;
}

完整代码

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

#ifdef DEBUG
#define LOG(format, ...) \
do{                                                                                         \
    time_t t = time(0);                                                                     \
    struct tm ptm;                                                                          \
    memset(&ptm, 0, sizeof(ptm));                                                           \
    localtime_r(&t, &ptm);                                                                  \
    printf("[LOG][%4d-%02d-%02d %02d:%02d:%02d][%s:%s:%d]:\033[31m " format "\033[0m", \
            ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday, ptm.tm_hour,                   \
            ptm.tm_min, ptm.tm_sec, __FILE__, __FUNCTION__ , __LINE__, ##\_\_VA\_ARGS\_\_); \
    fflush(stdout);                                                                         \
}while(0)
#else
#define LOG(format, ...) 
#endif



![img](https://img-blog.csdnimg.cn/img_convert/e6904d03fa76d156b51f98a323ec1621.png)
![img](https://img-blog.csdnimg.cn/img_convert/2e6d771be07d72e9835e23d309e6306e.png)
![img](https://img-blog.csdnimg.cn/img_convert/b488ee104a1efdaec24768786c746722.png)

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

WzN-1725999996551)]
[外链图片转存中...(img-LQT5CYgI-1725999996551)]
[外链图片转存中...(img-vf1jNhzE-1725999996551)]

**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!**

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值