一.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
普通字符:''
属性字符: ''|属性
特殊的属性字符:比如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()关闭属性
这组函数一定要在initscr后调用
背景函数:
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(); }
案例:
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(); }
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,结束功能