🔥博客主页: 我要成为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_file1
、source_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系统函数中的open,read,write实现简单的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:数组的长度,即字符串的个数。
代表的是我们在终端输入命令时,读取到的命令的个数,按空格来区分。
例如一个简单的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;
}
尝试拷贝源文件到一个已经存在的文件
尝试拷贝源文件到一个不存在的文件
默认掩码
为什么open函数的第三个参数,mode,我们传入的是0777,但是实际创建的确实0755?
因为系统有默认的掩码,对权限进行遮掩。我们在函数中用umask修改一下即可。
再次拷贝文件查看权限:
修改成功!
如何查看错误码
在Linux下,如果我们输入一个错误的命令,终端会告诉我们错误信息。
如果我们自己实现的命令,如何获取错误信息呢?
需要使用errno获取错误码
我们需要引入头文件errno.h,然后在出错的地方打印错误码即可。
第一种方式
需要用到string.h里的strerror函数,将错误码转换成错误信息。
第二种方式
用error.h里的perror函数打印错误信息
我们尝试拷贝一个不存在的文件:
成功显示出了错误码