linux高階程式設計day04 筆記(轉)
一.IO與檔案對映
1.IO的共享與效率
read與write其中資料緩衝的大小
讀取資料的緩衝大小:getpagesize。
2.定位與定位讀取(隨機讀取)
read與write在操作的時候,自動移動讀取位置.
lseek改變讀取位置.
pread/pwrite在指定位置讀寫。
2.1.lseek的函式說明:
int fd,//定位檔案描述符號 off_t off,//定位位置 int whence//定位參照點:檔案開始位置/檔案結束位置/檔案當前位置
返回當前讀取位置在檔案中的絕對位置.
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
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
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,結束功能