设备文件
Linux把所有设备都映射成了文件
设备文件一般存储在 /dev 目录下
我们可以像操作文件一样操作他们
ls /dev –l
brw-rw---- 1 root disk 8, 0 Dec 21 20:00 sda
crw--w---- 1 root tty 4, 0 Dec 21 20:00 tty0
b 表示块设备文件
c 表示字符设备文件
区别:
块设备
1.主要用于随机存取。
2.将信息存储在定长块内,IO操作通过内核IO缓冲完成,可以对文件任意位置进行任意长度的 IO操作。
3.比如磁盘。
字符设备
1.主要用于顺序存取。
2.无内核缓冲,只能顺序存取。IO操作的长度为设备要求的块长的整数倍。
3.比如终端,打印机,网络接口等
设备文件操作流程
打开: fd = open(devName, O_RDWR)
备份: ioctl(fd, TCGETA, &oldAttr);
设置: ioctl(fd, TCSETA, &newAttr);
读: read(fd, buf, len);
写: write(fd, buf, len);
恢复: ioctl(fd, TCSETA, &oldAttr);
关闭: close(fd)
终端设备操作
include<unistd.h>
ioctl(int fd, int cmd, struct termio *arg)
cmd 参数
TCGETA 获取终端信息
TCSETA 写入终端信息
TCSETAW 先将当前输入队列发送完毕,再写入设置
TCSETAF 先将当前输入队列清空,再写入设置
include<termio.h>
struct termio 解析:
struct termio
{
unsigned short c_iflag; //终端输入方式
unsigned short c_oflag; //终端输出方式
unsigned short c_cflag; //终端控制方式
unsigned short c_lflag; //行规则模式
char c_line;
unsigned char c_cc[NCC]; //控制字符
}
例子:只允许输入小写,大写变小写
void Test_iflag ()
{
int fd;
struct termio new,old;
char buf[128];
//获取当前的设备old
ioctl(STDIN_FILENO,TCGETA,&old);
//用new接受old,否则new=NULL;
new=old;
//设置小写风格,所有输入均为小写
new.c_iflag|=IUCLC;
ioctl(STDIN_FILENO,TCSETA,&new);
scanf("%s",buf);
printf("change buf:%s ",buf);
//恢复原来的设备
ioctl(STDIN_FILENO,TCSETA,&old);
scanf("%s",buf);
printf("resume buf:%s ",buf)
}
例子:只允许输出大写,小写变大写
void Test_oflag()
{
struct termio new,old;
char *buf="hello world";
printf("oginal buf:%s ",buf);
ioctl(STDOUT_FILENO,TCGETA,&old);
new=old;
new.c_oflag|=OLCUC;
ioctl(STDIN_FILENO,TCSETA,&new);
printf("big buf:%s ",buf);
ioctl(STDIN_FILENO,TCSETA,&old);
printf("resume buf:%s ",buf);
}
注意:
默认ICANON,输入模式为标准模式,有缓冲
设置为 ~ICANON,则输入模式为原始输入,无缓冲
例子1:按下字符,立马输出对应的ASCII,不需要按回车,回车键结束
void Test_lflag()
{
struct termio new,old;
ioctl(STDOUT_FILENO,TCGETA,&old);
new=old;
new.c_lflag&=~ICANON;
ioctl(STDIN_FILENO,TCSETA,&new);
char ch=0;
while(ch!=' ')
{
scanf("%c",&ch);
printf("-->%d ",ch);
}
ioctl(STDIN_FILENO,TCSETA,&old);
}
例子2:模拟密码,无显示密码的输入。
new.c_lflag&=~ECHO;
ioctl(STDIN_FILENO,TCSETA,&new);
char pPassWd[16];
printf("input password :");
scanf("%s",pPassWd);
printf("password :%s ",pPassWd);
ioctl(STDIN_FILENO,TCSETA,&old);
例子:当输入超过5个字符或输入字符且超过5秒无操作,提示超时。
注意:输入的字符要在缓冲区中为准。即“sdsasddsad”没有按下回车,只在终端显示,该属性不响应。因此new.c_lflag&=~ICANON;设置为原始输入且使用read(STDIN_FILENO,buf,128),而不是scanf();
void Test_cc()
{
struct termio new,old;
char buf[128];
ioctl(STDIN_FILENO,TCGETA,&old);
new=old;
new.c_lflag&=~ICANON;
new.c_cc[VMIN]=5; //5个字符
new.c_cc[VTIME]=50; //单位是0.1秒,50即5秒
ioctl(STDIN_FILENO,TCSETA,&new);
read(STDIN_FILENO,buf,128);
printf(" over time");
ioctl(STDIN_FILENO,TCSETA,&old);
}
补充:
printf在终端输出时改变颜色
终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关。
转义序列是以 ESC 开头,可以用 33 完成相同的工作(ESC 的 ASCII 码用十进制表示就是 27, = 用八进制表示的 33)。
注意:
[:开始设置的标识;m:结束设置的标志;设置之间使用分号。