linux文件管理小结之自定义more

** _ 1.more命令功能 _ **

more命令用于查看内容超过一屏的文本(类似于cat)
** 基本功能 ** :
1.输入backspace :内容翻一屏
2.输入enter : 内容翻一行
3.输入q:退出
4.实时显示已读文件比例

** _ 2.实现思路 _ **

  1. 从命令中获取需要操作的文件
  1. 打开文件:open(filename,O_RDONLY);
  1. 获取文件总行数:
    lseek(fd,0,SEEK_END);//移动文件指针至文件末
    page_sum = lseek(fd,0,SEEK_CUR);//计算与文件头偏移量,即可得到文件总行数
  1. 命令初始读取内容(定义整屏为10行)
    设置一标志量 存储 每次需要显示的行数,假设n,则执行n次下操作
    用read(fd,str,1); 每次读取一个字节,读到’\n’停止
    并且在每次读完之后需要用lseek(fd,0,SEEK_CUR)来获取当前已显示行数,用于得到文件已阅比例
  1. 每次操作完成后接受用户指令
    see_more();
    函数接受用户输入,根据输入值返回要翻的页数
  1. close(fd);

** _ 过程收获 _ **

  1. 反显文字:
    做这个时才了解到linux 上 printf的功能好丰富,清屏,移动光标,一应俱全;
  1. 保证more的提示信息总显示在终端的最下端,并不重复显示
    刚开始准备使用,printf(“\033[s”)记录光标位置,输出后,再用printf(“\033[u\033[K”);光标归位并清行;
    然而在输出提示信息中,还需要接受用户的输入,会产生换行符,而换行之后,光标归位会失效,记录于此。
    最终是用printf(“\033[1A\033[K”)将光标上移一行,并清空该行内容,用以覆盖提示信息
  1. 文件比例的实现
    这个的实现细节上文已经提到,之所以再做赘述,是因为笔者在实现过程中因为此功能卡顿很久
    因为需要按行读的缘故,想要使用fgets()来读取文本,但是打开文件又用的是系统函数open(),而非fopen(),于是就产生了混用的情况。
    而结果是每次用lseek()读取当前文件指针偏移量时,得到的值都是文件首与文件尾的偏移量,改为fseek()后,值变为0,探究无果,不知其因,记录于此,日后
    再谈

** _ 代码 _ **

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

#define PAGENUM 10 //定义一屏为10行

void do_more(int fd);
int see_more(  int sum, int now);

int main( int argc, char **argv )
{
    int fd;
    if( argc == 1 )//参数不合法则返回
    {
        return 0;
    }
    else
    {
        while( argc-->1 )
        {
            if( (fd = open(*++argv,O_RDONLY)) != -1 )
            {
                do_more(fd);
                close(fd);
            }
            else
            {
                printf("Error: can't open file\n");
                exit(1);
            }
        }
    }
    return 0;
}

void do_more(int fd)
{
    char str[3];
    int page_num = 0;//保存每次需要跳转的行数
    int rel;
    int page_now = 0;//保存当前行数(初始为0)
    int page_sum;//保存总行数


    lseek(fd,0,SEEK_END);//移动文件指针至文件末
    page_sum = lseek(fd,0,SEEK_CUR);//计算与文件头偏移量,即文件总行数
    lseek(fd,0,SEEK_SET);//移动文件指针至文件头

    while( page_now<page_sum )
    {
        while(read(fd,str,1))//每次读一行
        {
            if(str[0] =='\n')
            {
                printf("\n");
                break;
            }
            printf("%c",str[0]);
        }
        page_now = lseek(fd, 0, SEEK_CUR);//实时更新已读行数
        if( page_num == PAGENUM )
        {
            rel = see_more( page_sum, page_now);//获取用户输入
            printf("\033[1A\033[K");//将光标上移一行,并清空该行内容,用以覆盖提示信息
            if( rel == 0 )
            {
                break;
            }
            else
            {
                page_num -= rel;
            }
        }
        page_num++;
    }
}

int see_more(int sum,int now)
{
    int rel;
    printf("\033[7m --更多-- enter翻行 backspace翻页 q退出  %.2f%% \033[0m",now*100.0/sum);//反显输出提示信息以及文件已读比例

    while(rel = getchar())
    {
        if(rel == 'q')
        {
            return 0;
        }
        if(rel == ' ')
        {
            return PAGENUM;
        }
        if(rel == '\n')
        {
            return 1;
        }
    }

    return 0;
}