1. 程式人生 > >linux高階程式設計day04 筆記(轉)

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