🔥博客主页: 我要成为C++领域大神
🎥系列专栏:【C++核心编程】 【计算机网络】 【Linux编程】 【操作系统】
❤️感谢大家点赞👍收藏⭐评论✍️
本博客致力于分享知识,欢迎大家共同学习和交流。
cat
是一个常用的命令行工具,用于显示文件内容、将多个文件连接成一个文件以及创建文件。cat
的名称来自于 "concatenate",表示它的原始目的是连接文件。
cat
命令的基本用法和功能:
显示文件内容:
使用 cat
命令可以显示一个或多个文件的内容。例如:
cat filename
这将会显示 filename
文件的内容到标准输出(终端)上。
连接多个文件:cat
命令还可以将多个文件的内容连接起来,并将结果输出到标准输出上。例如:
cat file1 file2 > output_file
这将会将 file1
和 file2
文件的内容连接起来,并将结果写入到 output_file
文件中。
创建文件:
如果将 cat
命令用于一个尚不存在的文件,它会创建一个新文件。例如:
cat > new_file
在这种情况下,cat
命令将会从标准输入中读取内容,直到遇到 EOF(Ctrl+D),然后将这些内容写入到 new_file
文件中。
显示行号:
使用 -n
选项可以显示文件内容,并在每行前面加上行号。例如:
cat -n filename
显示特殊字符:
使用 -v
选项可以显示文件中的不可见字符和特殊字符。例如:
cat -v filename
我们将用C语言系统函数中的open,read,write,lseek实现简单的cat命令:显示文件内容。
先来了解一下函数
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),
非阻塞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是请求写入的字节数。
lseek
1、功能::用于在文件中移动文件指针的位置,以便进行读取或写入操作。通过指定偏移量,可以将文件指针移动到文件的特定位置,例如文件开头、当前位置或文件末尾。
2、头文件: #include <unistd.h>
3、函数定义:
off_t lseek(int fd, off_t offset, int whence);
lseek
函数接受三个参数:文件描述符 fd
、偏移量 offset
和移动方式 whence
。
4、返回值:lseek
函数的返回值是 off_t
类型,表示成功移动文件指针后的新位置。如果出错,则返回 -1,并设置全局变量 errno
指示错误类型。
5、参数说明:
fd
:要操作的文件的文件描述符,它是通过 open
等函数打开文件时返回的。
offset
:要移动的字节数,可以为正数、负数或零。正数表示向文件末尾方向移动,负数表示向文件开头方向移动,零表示不移动。
whence
:指定移动文件指针的方式。有三种可能的取值:
SEEK_SET
:从文件开头开始偏移,偏移量为 offset
字节。
SEEK_CUR
:从当前位置开始偏移,偏移量为 offset
字节。
SEEK_END
:从文件末尾开始偏移,偏移量为 offset
字节。
通过指定不同的偏移量和移动方式,lseek
函数可以在文件中灵活地定位到需要的位置,以便后续的读取或写入操作。
main函数的“参数”
在此之前,我们需要先了解一下main函数的参数。
main函数也是有参数的。
int main(int argc, char *argv[])
{
return 0;
}
char *argv[]:很明显,这是一个数组,char *类型的数组,数组内每个元素都是一个字符串
argc:数组的长度,即字符串的个数。
代表的是我们在终端输入命令时,读取到的命令的个数,按空格来区分。
例如一个简单的touch命令,argc=4,argv={"touch","aa","bb","cc"}。
函数实现
简单的cat命令
了解完原理之后,我们开始实现
第一步,需要判断命令是否合法,因为显示文件内容需要两个个参数(cat filename)
第二步,open函数以只读的方式打开文件,分配一个文件描述符,判断是否打开成功
第三步,read函数读取文件内容,write函数将内容输出到标准输出符(终端打印),循环读写,直到读取完毕
第四步,操作系统中可以打开的文件是有上限的,所以我们在操作完成之后,需要进行关闭文件。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc, char *argv[]) // 从命令行获取参数
{
// 1、打开文件
int fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
printf("file open fail\n");
return -1;
}
char buf[4096] = "";
int nLength = 0;
while (1)
{
// 2、读取文件
nLength = read(fd, buf, sizeof(buf));
if (nLength == 0)
{
printf("read over.\n");
break;
}
if (nLength == -1)
{
printf("file %s read fail!\n", argv[1]);
return -1;
}
// 3、写到标准输出符
nLength = write(STDOUT_FILENO, buf, nLength);
if (nLength == -1)
{
printf("write fail!\n");
return -1;
}
}
// 4、关闭文件
close(fd;
return 0;
}
在终端打印出了对应文件的内容
从指定位置处开始显示
第一步,需要判断命令是否合法,因为显示文件内容需要两个个参数(cat filename)
第二步,open函数以只读的方式打开文件,分配一个文件描述符,判断是否打开成功
第三步,lseek函数指定光标位置和移动方式
第四步,read函数从指定位置开始读取内容,write函数将内容输出到标准输出符(终端打印),循环读写,直到读取完毕
第五步,操作系统中可以打开的文件是有上限的,所以我们在操作完成之后,需要进行关闭文件。
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
int main(int argc, char *argv[]) // 从命令行获取参数
{
// 1、打开文件
int fd = open(argv[1], O_RDONLY);
if (fd == -1)
{
printf("file open fail\n");
return -1;
}
// 表示从文件头到文件尾经过的大小
int size = lseek(fd, 0, SEEK_END);
// 打印文件大小
printf("file size=%d\n", size);
// 设定光标到文件开头第十个字符
lseek(fd, 10, SEEK_SET);
char buf[4096] = "";
int nLength = 0;
while (1)
{
// 2、读取文件
nLength = read(fd, buf, sizeof(buf));
if (nLength == 0)
{
printf("read over.\n");
break;
}
if (nLength == -1)
{
printf("file %s read fail!\n", argv[1]);
return -1;
}
// 3、写到标准输出符
nLength = write(STDOUT_FILENO, buf, nLength);
if (nLength == -1)
{
printf("write fail!\n");
return -1;
}
}
// 4、关闭文件
close(fd);
return 0;
}
代码里我们设置光标第十个字符开始
正确打印了文件大小
如何查看错误码
在Linux下,如果我们输入一个错误的命令,终端会告诉我们错误信息。
如果我们自己实现的命令,如何获取错误信息呢?
需要使用errno获取错误码
我们需要引入头文件errno.h,然后在出错的地方打印错误码即可。
第一种方式
需要用到string.h里的strerror函数,将错误码转换成错误信息。
第二种方式
用error.h里的perror函数打印错误信息
我们尝试cat一个不存在的文件:
成功显示出了错误码