C++学习:第六章Linux高级编程 - (四)文件映射、文件描述符、curses

一、IO与文件映射

     1. IO的共享与效率

          read与write其中数据缓冲的大小

          读取数据的缓冲:getpagesize。一般用它的返回值大小设置为缓冲大小就可以,也可以为一个页大小。

     2. 定位与定位读取(随机读取)

          read与write在操作的时候,自动移动读取位置.

          lseek改变读取位置.

          pread/pwrite在指定位置读写。

          ssize_t pread(intfd, void *buf, size_tcount, off_toffset);

          ssize_t pwrite(intfd, const void *buf, size_tcount, off_toffset);

          2.1 lseek的函数说明:

               off_t  lseek(

                    int fd,           //定位文件描述符号

                    off_t off,             //定位位置

                    int whence       //定位参照点:SEEK_SET 文件开始位置/SEEK_END 文件结束位置/SEEK_CUR文件当前位置

          );

          返回:

               返回当前读取位置在文件中的绝对位置.

          2.2 lseek(是小写的L)的作用:定位文件的位置

               问题:lseek的定位的位置超出文件的大小范围?

               lseek移动位置只要合法,都是有效

          2.3 lseek+write=pwrite

               lseek+read =pread

          2.4 案例:

               读取一个特殊的文件:

               /proc/${pid}/mem文件程序的虚拟内存文件

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

int a=9999;

main()
{
    char filename[100];
    int fd;
    int data=8888;

    //得到文件名
    sprintf(filename,"/proc/%d/mem",getpid());

    //打开文件
    fd=open(filename,O_RDWR);
    if(fd==-1) printf("open error:%m\n"),exit(-1);

    //读取a地址这个位置的数据
    //pread(fd,&data,4,(int)&a);
    //lseek(fd,(int)&a,SEEK_SET);
    //read(fd,&data,4);
    //write(fd,&data,4);

    pwrite(fd,&data,4,(int)&a);//00
    printf("%d\n",a);//输出9999,这是因为在00位置程序没有写的权限
    printf("%d\n",data);//输出9999

    close(fd);
}

     3. 文件的其他操作

          fstat              获取文件状态

          ftruncate              改变文件大小

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

main()
{
    int fd;
    struct stat st;

    fd=open("stu.dat",O_RDONLY);
    if(fd==-1) printf("err:%m\n"),exit(-1);

    fstat(fd,&st);
    printf("%d,%o\n",st.st_size,st.st_mode);

    close(fd);
}

     4. 文件映射:

          虚拟地址映射到内存。

          虚拟地址可以映射到文件:可以用内存方式访问文件.

          mmap/munmap

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

struct stu
{
    char name[20];
    int  age;
    float score;
};

main()
{
    int fd;
    struct stu *s;//文件在虚拟内存的映射首地址
    struct stat st;
    int size;//文件大小
    int count;//记录条数
    int i;

    //1.打开文件
    fd=open("newstu.dat",O_RDWR|O_CREAT|O_EXCL,0666);
    if(fd==-1)
    {
        fd=open("newstu.dat",O_RDWR);
        if(fd==-1) printf("::%m\n"),exit(-1);
    }

    //2.得到文件大小,文件记录条数
    fstat(fd,&st);
    size=st.st_size;
    count=size/sizeof(struct stu);

    //3.文件大小改变只要在munmap之前调用都有效
    //ftruncate(fd,size+sizeof(struct stu));

    //4.映射到一个虚拟的地址
    s=mmap(0,size+sizeof(struct stu),
        PROT_READ|PROT_WRITE,
        MAP_SHARED,fd,0);

    //5.把数据写入虚拟地址
    printf("输入姓名:");
    scanf("%s",s[count].name);

    printf("输入年龄:");
    scanf("%d",&(s[count].age));

    printf("输入成绩:");
    scanf("%f",&(s[count].score));

    ftruncate(fd,size+sizeof(struct stu));//比较好的位置

    for(i=0;i<count;i++)
    {
        printf("%s,\t,%d,\t%.2f\n",
        s[i].name,s[i].age,s[i].score);
    }    

    //6.卸载虚拟地址
    munmap(s,sizeof(struct stu)+size);

    //7.关闭文件
    close(fd);
}

二、文件描述符号的操作(IO锁)

     文件描述符号是整数。文件描述符号对应内核的上下文环境。

     1. dup    dup2拷贝文件描述符号

          dup        拷贝文件符号,返回系统指定的整数

          dup2      拷贝文件描述符号,返回用户指定的整数

     2. fcntl对文件描述的属性的修改

          2.1 拷贝文件描述符号

          2.2 修改判定文件的描述标记

          2.3 修改判定文件的状态标记

               不可修改:O_RDONLY O_WRONLY _ORDWR  O_CREAT O_EXCL

               可以修改:O_APPEND O_ASYN

          2.4 设置强制锁(重新编译内核)

          2.5 设置建议锁(默认)

          2.6 设置的信号

三、IO与Curses(介绍)

     Curses:CUI(字符UI)

     UI:User Interface.分类

     CUI:字符界面

     GUI:图形界面      

     使用一套封装库  libcurses.so

          在/usr/lib目录下

     编译只需要指定-lcurses

     老版本:     libcurses.so

     新的版本: ibncurses.so

     如果头文件curses.h不存在,请尝试使用ncurses.h

     如果库文件curses  不存在,请尝试使用ncurses

     printf / scanf标准IO

     大部分标准IO重定向到终端./dev/tty      /dev/pts/1

     curses就是终端输出.

          -lcurses  -ncurses

     为了防止printf重定向到终端破坏UI,禁止在curses中使用标准IO.

     1. 编程模型

          初始化终端 initscr

          操作终端     (输入/输出/定位/刷新....)

          释放终端     endwin

     2. 显示

          2.1 图形输出

               border

               box

               hline

               vline

               属性字符:字节 = 属性字节 + 字符字节

               注意:

                    box需要窗体.

                    initscr返回被初始化的窗体:标准屏幕WINDOW*

                    实际上curses定义一个全局变量stdscr就是标准屏幕

               函数命名规则:

                    ****                        标准屏幕stdscr

                    w****                    指定窗体

                    mv****                  指定位置

                    mvw****               指定窗体的指定位置

          2.2 刷屏

               void refresh()

               void wrefresh(WINDOW*);

               从里到外刷屏

#include <curses.h>

int main()
{
    initscr();//初始化终端

    //border(0,0,0,0,0,0,0,0);//默认参数
    border('a','b','c','d','e','f','g','h');
    box(stdscr,0,0);
    mvhline(2,10,'=',20);
    mvvline(2,10,'|',10);
    refresh();

    //wrefrsh(stdscr);
    getch();//等待一个字符输入
    endwin();//释放终端
    return 0;
}

          2.3 字符输出

               addch

               普通字符:''

               属性字符:''|属性

               特殊的属性字符:比如ACS_PI

          2.4 字符串输出

               int addstr(const char *);

          2.5.格式字符串输出

               int printw(const char*,....);

     3. 字符属性与颜色

          颜色属性

          3.1 判定终端是否支持颜色

               bool has_colors();       //都支持颜色,建议不判定

          3.2 初始化颜色:

               int start_color();

          3.3 定义颜色对

               int init_pair(short pair,short fore,short back);

          3.4 使用颜色对

               COLOR_PAIR(short pair)

          3.5 设置属性

               attron()开启属性

               attroff()关闭属性

               这组函数一定要在initscr后调用

          3.6 背景函数:

               bkgd();

#include <curses.h>

int main()
{
    initscr();

    if(has_colors()==TRUE)
    {
        start_color();
        init_pair(1,COLOR_RED,COLOR_WHITE);
        init_pair(2,COLOR_BLUE,COLOR_GREEN);
        init_pair(3,COLOR_BLACK,COLOR_WHITE);
        bkgd(COLOR_PAIR(3));
    }

    box(stdscr,0,0);
    mvaddch(2,10,ACS_PI|COLOR_PAIR(1));
    mvaddch(2,11,ACS_PI|COLOR_PAIR(2));
    attron(COLOR_PAIR(1));
    mvaddstr(5,10,"Hello 世界!");
    attroff(COLOR_PAIR(1));
    attron(COLOR_PAIR(2)|A_UNDERLINE);
    mvaddstr(7,10,"Hello Fellow!");
    attroff(COLOR_PAIR(2)|A_UNDERLINE);
    mvprintw(9,10,"行:%d,列:%d",LINES,COLS);

    getch();
    endwin();
}

     4. 案例:

          4.1 时间显示屏幕

               1.初始化

               2.循环显示时间,并且睡眠1秒

               3.释放

#include <curses.h>
#include <time.h>
#include <unistd.h>

void init();
void drawui();
void business();
void destroy();

main()
{
    init();
    drawui();
    business();
    destroy();
}

void business()
{
    time_t tt;
    struct tm *t;
    while(1)
    {
        //取时间
        tt=time(0);
        t=localtime(&tt);

        //显示时间
        mvprintw(LINES/2,(COLS-8)/2,
            "%02d:%02d:%02d",
            t->tm_hour,t->tm_min,t->tm_sec);

        //刷新屏幕
        refresh();
        sleep(1);

    }
}

void drawui()
{
    box(stdscr,0,0);
}

void destroy()
{
    endwin();
}

void init()
{
    initscr();
}

          4.2 登录界面

               1. 初始化

               2 绘制界面

                    头

                    绘制用户名输入区

                    绘制密码输入区

               3.等待输入

               4.结束

#include <curses.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

void init();
void drawLogin();
void destroy();

main()
{
    init();
    drawLogin();
    destroy();
}

void drawLogin()
{
    char *heads="联通BSS业务支撑系统";
    char *user="用户[           ]";
    char *pass="口令[           ]";

    box(stdscr,0,0);
    attron(A_BOLD);
    mvaddstr(3,(COLS-strlen(heads))/2,heads);
    mvhline(4,(COLS-strlen(heads))/2,0,strlen(heads));
    attroff(A_BOLD);
    mvaddstr(8,(COLS-strlen(user))/2,user);
    mvaddstr(10,(COLS-strlen(pass))/2,pass);
    refresh();
}

void destroy()
{
    getch();
    endwin();
}

void init()
{
    initscr();
}

     5. 输入

          5.1 字符输入

               int getch();

               返回的是字符

               禁止回显noecho

               使功能键有效,使用keypad(WINDOW*,bool)

#include <curses.h>

main()
{
    int ch;

    //初始化
    initscr();
    noecho();

    //循环输入
    while(1)
    {
        ch=mvgetch(5,10);
        //循环显示输入
        mvprintw(8,10,"你输入的是:%c(%d)",ch,ch);
    }    

    //释放
    endwin();

}

          5.2 字符串输入

               int addstr

          5.3 格式数据输入

               scanw

#include <curses.h>

main()
{
    char name[9]={0};
    int r;
    initscr();

    //绘制UI
    mvaddstr(4,10,"用户:[        ]");

    //输入
    r=mvgetnstr(4,16,name,8);
    //name[r]=0;

    //打印输入
    mvprintw(7,10,"你输入的是:%s",name);
    refresh();

    //输入字符
    getch();

    endwin();
}

     6. 案例:

          使用键盘控制字母在屏幕上的移动

          补充:

               curses屏幕清除:man 3 clear

                    clear

                    erase

               光标控制:

                    得到光标位置           getsyx

                    设置光标的位置              setsyx

                    控制光标是否可见   curs_set();

#include <curses.h>

main()
{
    int ch;
    int x=5,y=5;

    initscr();
    keypad(stdscr,TRUE);
    curs_set(0);
    noecho();
    mvaddch(y,x,'A');

    while(1)
    {
        ch=getch();
        //mvaddch(y,x,' ');
        //clrtoeol();

        erase();
        //clear();

        switch(ch)
        {
            case KEY_UP:
                y--;
                break;

            case KEY_DOWN:
                y++;
                break;

            case KEY_LEFT:
                x--;
                break;

            case KEY_RIGHT:
                x++;
                break;

        }

        mvaddch(y,x,'A');
        refresh();
    }
    endwin();
}
#include <curses.h>

void init();
void drawUi();
void dealInput();
void destroy();

main()
{
    init();
    drawUi();
    dealInput();
    destroy();
}

void dealInput()
{
    int a,b;

    while(1)
    {
        mvaddstr(2,3,"     ");
        mvscanw(2,3,"%d",&a);
        mvaddstr(2,11,"     ");
        mvscanw(2,11,"%d",&b);
        mvaddstr(2,19,"      ");
        mvprintw(2,19,"%d",a+b);
        refresh();
    }
}

void drawUi()
{
    mvaddstr(2,2,"[     ]+[     ]=[      ]");
    refresh();
}

void destroy()
{
    endwin();
}

void init()
{
    initscr();
}

     7. 窗口

          subwin()        //创建子窗体(坐标采用标准屏幕坐标)

          derwin()       //创建子窗体(坐标采用父窗体坐标)

#include <curses.h>

main()
{
    WINDOW *w;
    initscr();
    box(stdscr,0,0);

    w=derwin(stdscr,4,20,5,3);
    box(w,0,0);

    refresh();
    wrefresh(w);
    getch();
    endwin();
}

一.目录管理

              目录遍历

二.进程

              1.进程的创建

              2.进程的应用

              3.进程的基本控制                                                

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页