• linux高级编程day04 笔记


    一.IO与文件映射
     1.IO的共享与效率
      read与write其中数据缓冲的大小
      读取数据的缓冲大小:getpagesize。 
     2.定位与定位读取(随机读取)
      read与write在操作的时候,自动移动读取位置.
      lseek改变读取位置.

      pread/pwrite在指定位置读写。
      2.1.lseek的函数说明: 

                    off_t   lseek(
                        int fd,//定位文件描述符号
                        off_t off,//定位位置
                        int whence//定位参照点:文件开始位置/文件结束位置/文件当前位置
                                            //SEEK_SET    SEEK_END  SEEK_CUR
                        );

        返回:
           返回当前读取位置在文件中的绝对位置.
      2.2.lseek的作用:定位文件的位置
        问题:lseek的定位的位置超出文件的大小范围?
        lseek移动位置只要合法,都是有效
      2.3.lseek+write=pwrite
          lseek+read =pread

    View Code
    #include <stdio.h>
    #include <fcntl.h>
    #include <stdlib.h>
    main()
    {
        int fd;
        float score;
        int r;
        int i=0;
        fd=open("stu.dat",O_RDWR);
        if(fd==-1) printf("open error:%m\n"),exit(-1);
            
        //定位
        /*
        for(i=0;i<2;i++)
        {
            r=lseek(fd,i*28,SEEK_SET);    
            r=lseek(fd,24,SEEK_CUR); 
            //r=lseek(fd,i*28+24,SEEK_SET);
            //读取
            r=read(fd,&score,sizeof(float));
            //打印 输出
            printf("%.2f\n",score);
        }*/
        /*
        r=lseek(fd,-100,SEEK_SET);
        printf("%d\n",r);
        //write(fd,"Hello",5);
        */
        for(i=0;i<2;i++)
        {
            pread(fd,&score,sizeof(float),i*28+24);
            printf("%.2f\n",score);
            read(fd,&score,sizeof(float));
            printf("%.2f\n",score);
        }
        
        close(fd);
    }

      2.4.案例:
         读取一个特殊的文件:
           /proc/${pid}/mem文件程序的虚拟内存文件

    View Code
    #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);
        printf("%d\n",a);
        
        close(fd);
    }

      3.文件的其他操作
        fstat获取文件状态
        ftruncate改变文件大小

    View Code
    #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
      案例:
        1.使用内存方式写入数据 

    View Code
    #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);
    }    

    作业:
      -+
    2.使用内存方式读取数据
     
    二.文件描述符号的操作(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:User Interface.
       CUI:字符界面
       GUI:图形界面
     
     使用一套封装库  libcurses.so
     /usr/lib目录下
     
     编译只需要指定-lcurses
     老版本:libcurses.so
     新的版本:libncurses.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

    View Code
    #include <curses.h>
    int main()
    {
        initscr();//初始化终端
        //border(0,0,0,0,0,0,0,0);
        box(stdscr,0,0);
        mvhline(2,10,'=',20);
        mvvline(2,10,'|',10);
        refresh();
        //wrefrsh(stdscr);
        getch();//等待一个字符输入        
        endwin();//释放终端
        return 0;
    }

        属性字符:字节=属性字节+字符字节
       注意:
         box需要窗体.
         initscr返回被初始化的窗体:标准屏幕WINDOW*
         实际上curses定义一个全局变量stdscr就是标准屏幕 
       函数命名规则:
          ****   标准屏幕stdscr
          w****    指定窗体
          mv****  指定位置
          mvw****  指定窗体的指定位置
       2.2.刷屏
         void refresh()   
         void wrefresh(WINDOW*);
         
         从里到外刷屏
       2.3.字符输出
         addch
         普通字符:''
         属性字符: ''|属性     
         特殊的属性字符:比如ACS_PI
       2.4.字符串输出
         int addstr(const char *);
       2.5.格式字符串输出
         int printw(const char*,....);  

    View Code
    #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();
    }

     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后调用
        
        背景函数:
          bkgd();

    View Code
    #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();
    }

    案例:
       1.时间显示屏幕
         1.初始化
         2.循环显示时间,并且睡眠1秒
         3.释放

    View Code
    #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();
    }

       2.登录界面
         1.初始化
         2.绘制界面
            头
            绘制用户名输入区
            绘制密码输入区
            
         3.等待输入
         4.结束

    View Code
    #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();
    }    

     4.输入
       1.字符输入
        int getch();
        返回的是字符
        禁止回显noecho
        使功能键有效,使用keypad(WINDOW*,bool)

    View Code
    #include <curses.h>
    main()
    {
        int ch;
        //初始化
        initscr();
        noecho();
        //循环输入
        while(1)
        {
            ch=mvgetch(5,10);
            //循环显示输入
            mvprintw(8,10,"你输入的是:%c(%d)",ch,ch);
        }    
        //释放
        endwin();
    }

    案例:
       使用键盘控制字母在屏幕上的移动
        
       补充:
         curses屏幕清除:man 3 clear
           clear
           erase 
         光标控制:
           得到光标位置  getsyx
           设置光标的位置 setsyx
           控制光标是否可见:curs_set();
           
       2.字符串输入
          int addstr
       
       3.格式数据输入
         scanw

    View Code
    #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();
    }

     5.窗口 
       subwin()//创建子窗体(坐标采用标准屏幕坐标)
       derwin()//创建子窗体(坐标采用父窗体坐标)

    View Code
    #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();
    }
    View Code
    #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();
    }    

    1.在vi设置编码:
      :set encoding=编码    gb2312  ios-8859-1  utf-8
    2.在编译器指定源文件的编码 -finput-charset=gb2312
    3.在终端指定编码:
    4.系统默认编码
      /etc/sysconfig/i18n配置编码
      
          
    作业:(使用文件映射) 
     1.使用内存方式读取数据
     2.使用curses+io完成:图书信息的录入
     3.使用curses+io显示图书信息:
        每次显示一条:
        使用up down键翻滚记录数据
     4.读取文件文件,使用curses 显示.
        实现如下功能:
           上下翻页功能
           输入q,结束功能 

  • 相关阅读:
    odoo 的各种domain
    odoo search之时间搜索,时间段查询
    git 修改远程仓库地址
    Windows 挂起进程
    结构体 偏移量 (size_t)&(((s *)0)->m) , list相关
    Data Flow Diagram with Examples
    Windows环境,获取当前线程的ID,GetCurrentThreadId
    获取 保存 系统信息 [Windows]
    notepad正则删除关键词所在行
    文件或文件夹改变后,发信号让系统刷新
  • 原文地址:https://www.cnblogs.com/tangzhengyue/p/2649193.html
Copyright © 2020-2023  润新知