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

#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文件程序的虚拟内存文件

#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改变文件大小

#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.使用内存方式写入数据 

#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

#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
     普通字符:''
     属性字符: '' | 属性 //位与,属性可以man attron查看可选属性    
     
     特殊的属性字符(特殊形状):比如ACS_PI

   2.4.字符串输出
     int addstr(const char *);
   2.5.格式字符串输出
     int printw(const char*,....);  

#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()关闭属性
      括号里传入所需要开启或者关闭的属性,      
      如:attron(COLOR_PARE(1));//开启颜色对1
    这组函数一定要在initscr后调用
    
    背景函数:
      bkgd();
#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.结束
#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)  

#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
#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()//创建子窗体(坐标采用父窗体坐标)

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

#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,结束功能 

 

你可能感兴趣的:(linux高级编程day04 笔记)