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

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

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

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

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

cat 是一个常用的命令行工具,用于显示文件内容、将多个文件连接成一个文件以及创建文件。cat 的名称来自于 "concatenate",表示它的原始目的是连接文件。

cat 命令的基本用法和功能:

显示文件内容
使用 cat 命令可以显示一个或多个文件的内容。例如:

cat filename

这将会显示 filename 文件的内容到标准输出(终端)上。

连接多个文件
cat 命令还可以将多个文件的内容连接起来,并将结果输出到标准输出上。例如:

cat file1 file2 > output_file

这将会将 file1file2 文件的内容连接起来,并将结果写入到 output_file 文件中。

创建文件
如果将 cat 命令用于一个尚不存在的文件,它会创建一个新文件。例如:

cat > new_file


在这种情况下,cat 命令将会从标准输入中读取内容,直到遇到 EOF(Ctrl+D),然后将这些内容写入到 new_file 文件中。

显示行号
使用 -n 选项可以显示文件内容,并在每行前面加上行号。例如:

cat -n filename

显示特殊字符
使用 -v 选项可以显示文件中的不可见字符和特殊字符。例如: 

cat -v filename

我们将用C语言系统函数中的openreadwrite,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一个不存在的文件:

成功显示出了错误码

  • 19
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值