【Linux】C语言系统函数实现cp命令

 🔥博客主页: 我要成为C++领域大神

🎥系列专栏【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】

❤️感谢大家点赞👍收藏⭐评论✍️

本博客致力于分享知识,欢迎大家共同学习和交流。

cp 命令是 Linux 和类 Unix 系统中常用的命令,用于复制文件和目录。

基本用法cp 命令的基本语法是将源文件复制到目标文件或目录中。

cp source_file target_file

这会将 source_file 复制到 target_file 中。如果 target_file 已经存在,将会被覆盖。

同时复制多个文件cp 命令可以同时复制多个文件到目标目录中。

cp source_file1 source_file2 ... target_directory

这会将 source_file1source_file2 等文件复制到 target_directory 目录中。

递归复制目录:如果 cp 命令的目标是一个目录,且使用了 -r--recursive 选项,cp 命令将会递归地复制整个目录结构。

cp -r source_directory target_directory

保留文件属性:使用 -p--preserve 选项可以保留源文件的属性(包括所有者、权限、时间戳等)。

cp -p source_file target_file

交互模式:使用 -i--interactive 选项可以在覆盖目标文件之前提示用户确认。

cp -i source_file target_file

显示复制过程:使用 -v--verbose 选项可以显示 cp 命令的复制过程。

cp -v source_file

我们将用Linux系统函数中的openreadwrite实现简单的cp命令:将源文件复制到目标文件

先来了解一下函数

open

1、功能:打开或创建一个文件。

2、头文件:

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

3、函数定义:

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

4、返回值:成功返回新分配的文件描述符,出错返回-1并设置errno

5、参数说明:

pathname参数是要打开或创建的文件名,可以是相对路径也可以是绝对路径。

flags参数有一系列常数值可供选择,可以同时选择多个常数用按位或运算符连接起来,所以这些常

数的宏定义都以O_开头,表示or。

必选项:以下三个常数中必须指定一个,且仅允许指定一个。

O_RDONLY:只读打开

O_WRONLY:只写打开

O_RDWR:可读可写打开

以下可选项可以同时指定0个或多个,和必选项按位或起来作为flags参数。

O_APPEND:表示追加。如果文件已有内容,这次打开文件所写的数据附加到文件的末尾而不覆盖

原来的内容。

O_CREAT:若此文件不存在则创建它。使用此选项时需要提供第三个参数mode,表示该文件的访

问权限。

O_EXCL:如果同时指定了O_CREAT,并且文件已存在,则出错返回。

O_TRUNC:如果文件已存在,并且以只写或可读可写方式打开,则将其长度截断(Trun-cate)为

0字节。

O_NONBLOCK:对于设备文件,以O_NONBLOCK方式打开可以做非阻塞I/O(Nonblock I/ O)

mode指定文件权限,可以用八进制数表示,比如0644表示-rw-r--r--

那么了解完open函数之后,想要实现简单的touch命令,我们需要调用open函数int open(const char *pathname, int flags, mode_t mode);并将第二个参数设置为O_CREAT,文件不存在则创建。
如果同时创建多个文件的话,那么需要循环创建。

read

1、功能:从打开的设备或文件中读取数据。

2、头文件:#include <unistd.h>

3、函数定义:ssize_t read(int fd, void *buf, size_t count);

4、返回值:成功返回读取的字节数,出错返回-1并设置errno,如果在调read之前已到达文件末尾,则

这次read返回0。

5、参数说明

① fd是要读取的文件的描述符。

② buf是要读取内容到哪个缓冲区。

③ count是请求读取的字节数,读上来的数据保存在缓冲区buf中,同时文件的当前读写位置向后

移。

write

1、功能:向打开的设备或文件中写数据。

2、头文件:#include <unistd.h>

3、函数定义:ssize_t write(int fd, const void *buf, size_t count);

4、返回值:成功返回写入的字节数,出错返回-1并设置errno(写常规文件时,write的返回值通常等于

请求写的字节数count,而向终端设备或网络写则不一定。)

5、参数说明

① fd是要写入的文件的描述符。

② buf是要写入内容存储在哪个缓冲区。

③ count是请求写入的字节数。

main函数的“参数”

在此之前,我们需要先了解一下main函数的参数。
main函数也是有参数的。

int main(int argc, char *argv[])
{
    return 0;
}

char *argv[]:很明显,这是一个数组,char *类型的数组,数组内每个元素都是一个字符串
argc:数组的长度,即字符串的个数。

代表的是我们在终端输入命令时,读取到的命令的个数,按空格来区分。

1f342d92460400fcd0545a464a1fdd60.png

例如一个简单的touch命令,argc=4,argv={"touch","aa","bb","cc"}。

函数实现

了解完原理之后,我们开始实现

第一步,需要判断命令是否合法,因为要拷贝需要三个参数(cp srcfile dstfile)

第二步,open函数打开源文件和目标文件,两个文件各分配一个文件描述符,判断是否打开成功

第三步,read函数从源文件读取内容,write函数将内容写入到目标文件,循环读写,直到读取完毕

第四步,操作系统中可以打开的文件是有上限的,所以我们在操作完成之后,需要进行关闭文件。

#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

int main(int argc,char * argv[]){
//1、判断参数是否合法
        if(argc!=3){
        printf("argc inputs illegal!\n");
        return -1;
        }
//2、打开源文件和目标文件,各分配一个文件描述符

     // 打开源文件,以只读的方式
      int fd_src=open(argv[1],O_RDONLY ,0777);
      // 判断返回值,失败就报错
      if(-1==fd_src){
     printf("file %s open fail\n",argv[1]);
      return -1;
      }

      // 打开目标文件,以 只写 | 不存在就创建 | 存在则覆盖 的方式创建
      int fd_dst=open(argv[2],O_WRONLY | O_CREAT | O_TRUNC ,0777);
      // 判断返回值,失败就报错
      if(-1==fd_dst){
     printf("file %s open fail\n",argv[2]);
      return -1;
      }
//3、进行循环读写操作,直到读取完毕
        char buf[4096]="";//定义读写缓冲区
        while(1){
        //进行读操作
        int nLength=read(fd_src,buf,4096);
        if(nLength==0)//说明读取完成,可以退出循环了
        {
        printf("file %s read success!\n",argv[1]);
        break;
        }
        if(nLength==-1)//读取失败
        {
        printf("read file %s fail.\n",argv[1]);
            return -1;
        }
        //进行写操作
        nLength=write(fd_dst,buf,nLength);
        if(nLength==-1){
        printf("write fail!\n");
        return -1;
        }
                }
        printf("copy success!\n");
//4、关闭文件
        close(fd_src);
        close(fd_dst);
        return 0;
}

尝试拷贝源文件到一个已经存在的文件

a16708a3c9b9de11a6f897f4dd1aab29.png

尝试拷贝源文件到一个不存在的文件

1bc14ebe97dd3b7685d312e4e4c5ea44.png

默认掩码

为什么open函数的第三个参数,mode,我们传入的是0777,但是实际创建的确实0755?

因为系统有默认的掩码,对权限进行遮掩。我们在函数中用umask修改一下即可。

1f72b94703e5a8fc13955e5351df9b35.png

再次拷贝文件查看权限:

4b3f22d153bc2ad0eb3f213a6b1dbac6.png

修改成功!

如何查看错误码

在Linux下,如果我们输入一个错误的命令,终端会告诉我们错误信息。

如果我们自己实现的命令,如何获取错误信息呢?

98372c9ac7bc268f415555a2274f5358.png

需要使用errno获取错误码

我们需要引入头文件errno.h,然后在出错的地方打印错误码即可。

第一种方式

需要用到string.h里的strerror函数,将错误码转换成错误信息。

0d117c306073c3324cf1b9c10cfa8291.png

第二种方式

用error.h里的perror函数打印错误信息

我们尝试拷贝一个不存在的文件:

5e878e28182064e02b424becbc89431e.png

成功显示出了错误码

  • 29
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值