设备文件和IO
1.在Linux下面一切都看成是文件,包括设备、soket、管道等等。
命令:
stat 文件名 (查看文件的节点号)节点号:IO Block
mknod 文件名 c 5 0(让普通的文件和设备进行关联)c:字符设备 5:主设备号,5是屏幕终端的设备 0:次设备号,表示第一块屏幕。让文件和显示设备关联。
2.C语言API:通过C库函数实现,基于系统调用上实现的。
系统调用:通过软中断的方式向内核提供请求,从而获取内核函数的服务入口。让系统从用户空间进入内核空间运行,运行后将结果返回给应用程序。
基于 基于 基于
bash---->Shell---->C---->系统调用
3.文件描述符(int类型)_fd
FILE指针里有个 文件描述符的东西(int类型)
打开文件的过程:
程序运行的时候给每个进程分配一个PCB(就是task_strut(包含有files的指针))
files指针用来保存打开文件的列表files_struct{fd[0],fd[1],fd[2]……}文件列表里包含有文件描述符0,1,2……
(0-stdin,1-stdout,2-stderr)每个进程被加载后,默认打开0,1,2这三个文件描述符。
打开第一个文件文件描述符为3;再打开一个文件文件描述符为4……(连续递增,知道达到#ulimit –n的限制为止)。
fd[1]--->file { f_flags(打开文件的标识读、写)
f_pos(文件打开的位置)
f_owner
f_count
f_dentry(文件路径)-->struct dentry{d_inode(编号:作用是帮我们找到文件在硬盘的位置)}
}
每个进程能够访问的文件描述符是有限制的,通过#ulimit –n可以查看和更改
以后操作文件都是通过文件描述符去操作。
open()打开系统调用
int open(const char *path, int flags);
path :文件的名称,可以包含(绝对和相对)路径
flags:文件打开模式
打开成功:返回文件描述符;
打开失败:返回-1
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
//***************************************课堂练习**********************************************
//****************2013.10.13.
//****************文件锁int fcntl(int fd, int cmd, struct flock *lock)
//***************************************课堂练习**********************************************
int main()
{
struct flock lock;
int fd = open("myfile1", O_RDWR | O_CREAT, S_IRWXU);
if (fd < 0) //打开失败返回-1,打开成功放回文件描述符
{
perror("文件打开失败!\n");
exit(-1);
}
memset(&lock, 0, sizeof(lock));
//读锁
fcntl(fd, F_GETLK, &lock);
//判断是否有锁
if (lock.l_type != F_UNLCK)
{
printf("File is lock! exit...");
exit(1);//有锁退出
}
//文件空锁状态,把锁设置成写锁
lock.l_type = F_WRLCK;
fcntl(fd, F_SETLK, &lock);
printf("Set lock!\n");
//延时5s来模拟文件锁起来了
sleep(5);
//把锁设置成空锁状态
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);
printf("Set unlock!\n");
close(fd);
return 0;
}
// struct flock
// {
// short l_type; /* 锁的类型 */
// short l_whence; /* 偏移量的起始位置: */
// off_t l_start; /* 从l_whence的偏移量 */
// off_t l_len; /* 从l_start开始的字节数 */
// pid_t l_pid; /* 锁所属进程ID(一般不用) */
// }
// l_type有F_RDLCK读锁、F_WRLCK写锁及F_UNLCK空锁。
// l_whence有SEEK_SET、SEEK_CUR和SEEK_END。
// l_len为0时表示从起点开始直至最大可能位置为止。
要求如下:
1、程序运行命令格式:
serialchat [-options];
[options]: p-输出打印serial.cfg各个配置项信息,格式:参数-----参数值;
s-进行菜单(有保存和退出)让用户设置;
f-指定配配置项设置,输出各选项置文件名,并输出各配置项信息
其他选项提示该程序用法帮助。
2、不支持serialchat运行两次
3、如果无法找到配置文件,则提示运行失败,原因:配置文件无法找到
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
typedef struct FILE_T
{
char *pos;
char *val;
}MYFILE;
bool readline(MYFILE *mfp, char *rslt);
char *ltrim(char *str);
int find(char *str, char ch);
int findstr(char *fstr, char *sstr);
void printmsg(char *str);
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("p-输出打印serial.cfg各个配置项信息,格式:参数-----参数值;\n"
"s-进行配置项设置,输出各选项菜单(有保存和退出)让用户设置;\n"
"f-指定配置文件名,并输出各配置项信息\n");
return 0;
}
if (strcmp(argv[1], "-p") != 0 &&
strcmp(argv[1], "-s") != 0 &&
strcmp(argv[1], "-f") != 0)
{
printf("p-输出打印serial.cfg各个配置项信息,格式:参数-----参数值;\n"
"s-进行配置项设置,输出各选项菜单(有保存和退出)让用户设置;\n"
"f-指定配置文件名,并输出各配置项信息\n");
return 0;
}
int fd;
struct flock lock; //文件锁
const char *fname = "serial.cfg"; //默认的文件
//-f选项
if (strcmp(argv[1], "-f") == 0)
{
char othername[100];
printf("输入配置文件名:");
scanf("%s", othername);
fname = othername; //默认的文件改文新的文件
}
if ((fd = open(fname, O_RDWR|O_EXCL)) == -1)
{
printf("没有该文件。\n");
return 1;
}
//文件上锁
memset(&lock, 0, sizeof(struct flock));
if (fcntl(fd, F_GETLK, &lock) == 0)
{
if (lock.l_type != F_UNLCK)
{
printf("文件被占用,退出程序\n");
close(fd);
return 1;
}
lock.l_type = F_WRLCK;
if (fcntl(fd, F_SETLK, &lock) != 0)
{
printf("锁住文件失败\n");
close(fd);
return 1;
}
char fval[4096] = {0};
read(fd, fval, 4095); //读文件
printmsg(fval); //打印配置文件内容。去除空格,去注释
if (strcmp(argv[1], "-s") == 0)
{
char key[20] = {0};
int keypos;
while (1)
{
printf("输入键名(key)(输入#exit退出):");
scanf("%s", key);
if (strcmp(key, "#exit") == 0)
{
break;
}
if ((keypos = findstr(fval, key)) != -1)
{
char val[20];
char *tmp = fval+keypos;
int pos = find(tmp, '=');
if (pos == -1)
{
printf("错误重新输入!\n");
continue;
}
printf("输入键值(val):");
scanf("%s", val);
memcpy(tmp+pos+1, val, strlen(val));
printmsg(fval);
char buf[10];
gets(buf);
printf("是否保存?(y/n):");
if (getchar() == 'y')
{
lseek(fd, 0, SEEK_SET);
write(fd, fval, strlen(fval));
printf("保存成功\n");
}
}
}
}
lock.l_type = F_UNLCK;
fcntl(fd, F_SETLK, &lock);
}
close(fd);
}
bool readline(MYFILE *mfp, char *rslt)
{
char *p = mfp->pos;
if (*p == '\0')
{
return false;
}
int i = 0;
while (*p != '\0' && *p != '\n')
{
rslt[i++] = *p;
p++;
}
rslt[i] = '\0';
if (*p == '\n')
{
p++;
}
mfp->pos = p;
return true;
}
char *ltrim(char *str)
{
while (*str == ' ')
{
str++;
}
return str;
}
int find(char *str, char ch)
{
int i = 0;
while (str[i] != ch && i < strlen(str))
{
i++;
}
if (str[i] == 0)
{
return -1;
}
return i;
}
int findstr(char *fstr, char *sstr)
{
int i = 0;
while (1)
{
if (fstr[i] == 0)
{
return -1;
}
if (memcmp(fstr+i, sstr, strlen(sstr)) == 0)
{
return i;
}
i++;
}
}
void printmsg(char *str)
{
int pos = 0;
int prev = 0;
MYFILE ff;
ff.pos = str;
ff.val = str;
char line[80];
while (readline(&ff, line))
{
char *tline = ltrim(line);
if (tline[0] == '#')
{
continue;
}
int pos;
if ((pos = find(tline, '=')) == -1)
{
continue;
}
char key[20] = {0};
memcpy(key, tline, pos);
char val[20] = {0};
memcpy(val, tline+pos+1, strlen(tline)-pos-1);
printf("%s = %s\n", key, val);
}
}