linux根据命令写功能,Linux_自己写一个more命令

1 分析

1.1 linux的more命令可以做什么?

more命令可以分页显示文本的内容,首先显示出第一页的内容,然后按回车显示下一行,按空格显示下一页,按q退出,按h显示帮助。同时,在显示的最下方显示文件的百分比

1.2 more是如何实现的

由more的功能可知,首先先输出一页,然后输出文件百分比,等待用户的输入,根据用户的输入进行下一步操作。

2 自己动手写一个more命令

2.1 实现打开文件

2.1.1 通过使用fopen函数来打开一个文件

#include

FILE*fopen(const char *path, const char *mode);

fopen是ANSIC标准中的C语言库函数,返回一个文件指针。

参数:

①path 文件的地址

② mode 文件打开的方式,共有一下几种

- r 以只读的方式打开文件,文件的读写位置为文件的开头

- r+ 以读写的方式打开文件,文件的读写位置为文件的开头

- w 以只写的方式打开文件并清除文件的内容,文件的读写位置为文件的开头

- w+ 以读写的方式打开文件,若文件存在就清除文件内容,若不存在及新建一个文件

- a 以追加的方式打开文件,若文件不存在就新建一个文件,文件的读写位置在文件的末尾

- a+ 以追加和读取的方式打开文件,读取的位置在文件的开头,写的位置仍然在文件的末尾

2.1.2 fopen与open的区别

333d7277499c0a79477c5fa3bc55407a.png

2.1.3 缓冲文件系统与非缓冲文件系统的区别

缓冲文件系统

缓冲文件系统是借助于文件结构体指针FILE *来对文件进行管理,通过文件指针对文件进行访问,即可以读写字符、字符串、格式化数据,也可以读写二进制数据。

缓 冲文件系统特点:在内存中开辟一个“缓冲区”,为程序里每一个文件使用,当执行读文件操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓 冲区”依次读入接收的变量。执行写文件操作时,也是先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大 小,影响着实际操作外在的次数,内存“缓冲区”越大,则操作外存的次数就越少,执行速度就越快,效率就越高。一般来说,文件“缓冲区”的大小跟机器是相关 的。

缓冲文件系统的IO函数主要包括:fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。

非缓冲文件系统

非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件(对于UNIX系统内核而言,文本文件和二进制代码文件并无区别),但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此,在读取正规的文件时,建议大家最好不要选择它。

非缓冲文件系统的IO函数主要包括:open, close, read, write, getc, getchar, putc, putchar等。

2.2 实现按行读取文件并显示

2.2.1 用fgets来读取文件中的一行

#include

char *fgets(char *s, int size,FILE*stream);

fgets从文件中最多读取size-1个字符,最后一个字符的位置用于存放’\0’作为结束。如果小于size,则一直读取到EOF或换行符,fgets也会将换行符写入到s中。

通过szie的限制,可以保证不会出现数组越界的情况。

参数:

①用于存放读取的数据

②读取的最大长度

③读取的文件

2.2.2 用fputs来显示到屏幕上

#include

int fputs(const char *s, FILE *stream);

fputs函数将s中的内容输出到stream中,以’\0’作为结束标志,但不会将其写入到文件中。

参数:

①将要写入的字符串

②写入的函数

2.3 输入的命令不显示并立刻执行而不需要输入回车

2.3.1 利用利用”tcgetattr”和”tcsetattr”函数改变终端的输入属性

#include

int tcgetattr(int fd, struct termios *termios_p);

int tcsetattr(int fd, int optional_actions,const struct termios *termios_p);

tcgetattr() 得到与 fd 指向的对象相关的参数,将它们保存于 termios_p 引用的 termios 结构中。函数可以从后台进程中调用;但是,终端属性可能被后来的前台进程所改变。

tcsetattr() 设置与终端相关的参数 (除非需要底层支持却无法满足),使用 termios_p 引用的 termios 结构。

参数:

optional_actions规定了何时应用这些变化,取值有

TCSANOW 立刻应用

TCSADRAIN 当所有的写入fd的输出被传输的时候生效,这个参数应当在改变影响输出的时候使用

TCSAFLUSH 当所有的写入fd的输出被传输时生效,并将所有未被读取的输入丢弃

termios结构体

这个结构体至少包括了以下四个变量

tcflag_t c_iflag; /* 输入模式 */

tcflag_t c_oflag; /* 输出模式*/

tcflag_t c_cflag; /* 控制模式 */

tcflag_t c_lflag; /* 本地模式 */

cc_t c_cc[NCCS]; /* 控制字符 */

有关该结构体的应用可以参阅man的在线帮助文档

2.4 显示已读部分的百分比

2.4.1 使用fseek,ftell函数获得文件的所有字符数

int fseek(FILE *stream, long offset, int whence);

long ftell(FILE *stream);

void rewind(FILE *stream);

介绍:

fseek是用于改变stream中读写指针的位置的函数。由whence规定的位置加上offset的大小就是新的位置,以字节为单位。

whence的取值:

SEEK_SET 文件的开始位置

SEEK_END 文件的结尾

SEEK_CUR 当前文件位置

ftell返回的是当前读写指针的之前所有字符的个数。

rewind 将读写指针放到文件的开头

2.4.2 获得已读字符的个数

设置一个变量用于记录字符的个数,每次输出就加上输出字符串的长度。

3 源码

#include

#include

#include

#include

#define MAXSIZE 1024//缓存的最大值

#define DEFAULT 10//默认显示的行数

void showTheFile(FILE *, int);

int getLineNum(FILE *, long, long);

void changeMode(int);

long getInputSize(FILE *);

int main(int argc, char *argv[])

{

FILE *fd = NULL;

if(argc == 1)

showTheFile(stdin, DEFAULT);

else

{

while(--argc)

{

fd = fopen(* ++argv, "r");

if(fd != NULL)

{

showTheFile(fd, DEFAULT);

fclose(fd);

}

else break;

}

}

return 0;

}

void showTheFile(FILE *fd, int linenum)

{

char buff[MAXSIZE];

int i = 0;

FILE *fdin = fopen("/dev/tty", "r");//打开tty文件获得用户的输入

long total = getInputSize(fd);

long readsize = 0;

if(fdin == NULL) return;

while(fgets(buff, MAXSIZE, fd)!=NULL)

{

if(i == DEFAULT)

{

linenum = getLineNum(fdin, total, readsize);

changeMode(1);

if(linenum == 0) break;

i-=linenum;

}

readsize+=strlen(buff);

if(!fputs(buff, stdout)) break;

i++;

}

}

int getLineNum(FILE *fdin, long total, long readsize)

{

double result = (double)readsize/(double)total;

result*=100;

printf("\033[33m --More--(%d%) \033[0m", (int)result);

char input;

changeMode(0);

while((input = getc(fdin))!=EOF)

{

int i;

switch(input)

{

case 'q':

return 0;

case ' ':

return 10;

case '\n' :

return 1;

}

}

}

void changeMode(int mode)

{

struct termios new;

struct termios old;

tcgetattr(0,&old);

new = old;

new.c_lflag &= ~(ICANON | ISIG);//不许需要输入回车并忽视Ctrl+C等终止符

new.c_cc[VTIME] = 0;

new.c_cc[VMIN] = 1;

if(mode == 0) new.c_lflag &= ~ECHO;不显示输入的值

if(mode == 1) new.c_lflag |= ECHO;

tcsetattr(0, TCSANOW, &new);

}

long getInputSize(FILE *input)

{

long size;

fseek(input, 0L, SEEK_END);

size = ftell(input);

rewind(input);

return size;

}

4 BUG

4.1 当输入回车或空格时,最下方显示的的more仍然会在上面显示

4.2 无法判断文件的类型,不论是否是文本文件都可以打开

4.3 无法根据终端的类型控制显示的行数

5 参考文献

Unix-Linux 编程实践教程

linux下改变终端的输入属性

【Linux开发习作】more命令的编写(2)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值