回顾:
Unix/Linux内存分配的函数和系统函数:
malloc() free()
sbrk() brk()
mmap() munmap()
今天:
文件描述符 - 对应一张文件表,文件信息存在文件表中,描述符只是文件表在进程文件总表中的编号,本质就是一个非负数
open() read() write() close() ioctl()
/* int open(const char *pathname, int flags); 函数原型
int open(const char *pathname, int flags, mode_t mode); */
int open(char* name,int flags,...)
name 就是文件名(带路径)
flags 常见值:(多个值用 | 连接)
O_RDONLY O_WRONLY O_RDWR 设定权限,必选其一
O_CREAT - 没有就新建,有就打开
O_EXCL - 辅助O_CREAT 没有就新建,有返回-1
O_TRUNC - 没有就新建,有就清空后打开
O_APPEND - 追加方式打开,一般是追加写
返回 可用的文件描述符 最小值,失败返回-1
注: 如果新建文件,需要第三个参数 -- 文件权限
常识:关于文件的操作,有两组信息
1.硬盘上的文件信息,比如文件大小,文件权限,文件的最后修改时间...;
2.内存中的文件描述符信息,比如:描述符权限(O_RDONLY等),文件偏移量...;
read() 和 write()
int read(int fd,void* buf,size_t count)
int write(int fd,void* buf,size_t count)
参数: fd - 文件描述符
buf - 任意类型的首地址
count - 对于read(),count是期望值
对于write(),count是实际值
返回真实的字节数(读/写),失败返回-1
read() 返回 0 代表读完
vi用wq保存退出时,多加一个换行符
练习:
1.员工管理系统 - 新增员工、查询员工信息
新增: 输入员工的信息,把信息保存到文件中,员工信息包括:员工编号、姓名、工资
查询: 把文件中的员工信息读出来并打印出有效信息
-----------------------------------------------------------
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 struct Data
6 {
7 int id;
8 char name[20];
9 double salary;
10 };
11
12 void add()
13 {
14 struct Data Data;
15 int fd = open("data",O_RDWR|O_CREAT|O_APPEND,0666);
16 if(fd == -1) perror("OPEN"),exit(-1);
17 printf("请输入ID:\n");
18 scanf("%d",&Data.id);
19 printf("请输入姓名:\n");
20 scanf("%s",Data.name);
21 printf("请输入工资:\n");
22 scanf("%lf",&Data.salary);
23 write(fd,&Data,sizeof(Data));
24 close(fd);
25 }
26
27 void query(int id)
28 {
29 struct Data Data;
30 int fd = open("data",O_RDONLY);
31 if(fd == -1) perror("OPEN"),exit(-1);
32 while(read(fd,&Data,sizeof(Data)))
33 {
34 if(Data.id == id)
35 break;
36 }
37 printf("ID:%d\n姓名:%s\n工资:%lg\n",Data.id,Data.name, Data.salary);
38 close(fd);
39 }
40 int main()
41 {
42 int x;
43 printf("输入 1 新增, 2 查询:\n");
44 scanf("%d",&x);
45 if(x==1)
46 {
47 while(x)
48 {
49 add();
50 printf("是否继续输入?(1/0)");
51 scanf("%d",&x);
52 }
53 }
54 else if(x==2)
55 {
56 printf("请输入查询ID:\n");
57 scanf("%d",&x);
58 query(x);
59 }
60 }
-----------------------------------------------------------
2.修改写文件的代码,实现 用cat命令查看时,能显示 可以看懂的信息。比如:
1,zhangfei,12000.000000
思路:sprintf() 只有字符串写入才能看懂
-----------------------------------------------------------
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <string.h>
6 struct Emp
7 {
8 int id;
9 char name[20];
10 double sal;
11 };
12 int main()
13 {
14 struct Emp em = {1,"zhangfei",12000.0};
15 int fd = open("data",O_RDWR|O_TRUNC);
16 if(fd == -1) perror("OPEN"),exit(-1);
17 char buf[100] = {};
18 sprintf(buf,"%d,%s,%lf",em.id,em.name,em.sal);
19 write(fd,buf,strlen(buf));
20 close(fd);
21 }
-----------------------------------------------------------
time a.out 可以测试程序运行时间,包括总时间,用户层时间和内核层时间
uc的文件读写函数在用户层是没有缓冲区的,如果频繁读写,需要程序员自定义缓冲区,而标C自身有缓冲区;
在系统中,文件描述符对应一张文件表,文件表中记录了描述符的信息和硬盘上文件的信息,定位硬盘上的文件/目录用i节点。ls -i 可以查看i节点,每张文件表 都有自己的偏移量
函数lseek()可以设定文件的偏移量
-----------------------------------------------------------
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5
6 int main()
7 {
8 int fd = open("a.txt",O_RDWR);
9 if(fd == -1) perror("OPEN"),exit(-1);
10 char ch;
11 read(fd,&ch,1); printf("%c\n",ch);//a
12 read(fd,&ch,1); printf("%c\n",ch);//b
13 lseek(fd,3,SEEK_CUR);
14 read(fd,&ch,1); printf("%c\n",ch);//f
15 lseek(fd,0,SEEK_SET);//回到开始
16 write(fd,"1",1);//a -> 1
17 lseek(fd,3,SEEK_SET); write(fd,"2",1);//d -> 2
18 lseek(fd,2,SEEK_CUR); write(fd,"3",1);//g -> 3
19 lseek(fd,-2,SEEK_CUR); write(fd,"4",1);//f -> 4
20 lseek(fd,-2,SEEK_END); write(fd,"5",1);//t -> 5
21 close(fd);
22 }
a.txt = abcdefghijklmnopqrst
经验: lseek()的 whence参数使用SEEK_SET
-----------------------------------------------------------
作业:
实现真实版的用户登陆和注册(文件版)
定义一个用户的结构,包括:用户名、密码、邮箱。读写基本单位是结构
用户注册模块 - 用户输入用户名、密码和邮箱,用追加方式写入文件,打印注册成功或失败
增强版:
1 加入密码确认,输入两次密码,两个字符串相等才能继续输入邮箱
2 加入用户名重复的过滤:如果用户名已经存在,那么告知用户,用户名已经被使用
思路: 写之前先读文件,读入一个数组,数组长度 文件大小/sizeof(结构)
用户登陆 - 读文件 ,读入一个数组,数组长度 文件大小/sizeof(结构)。再让用户输入用户名和密码,比较 用户名和密码都相等,登陆成功,否则登陆失败
Unix/Linux内存分配的函数和系统函数:
malloc() free()
sbrk() brk()
mmap() munmap()
今天:
文件描述符 - 对应一张文件表,文件信息存在文件表中,描述符只是文件表在进程文件总表中的编号,本质就是一个非负数
open() read() write() close() ioctl()
/* int open(const char *pathname, int flags); 函数原型
int open(const char *pathname, int flags, mode_t mode); */
int open(char* name,int flags,...)
name 就是文件名(带路径)
flags 常见值:(多个值用 | 连接)
O_RDONLY O_WRONLY O_RDWR 设定权限,必选其一
O_CREAT - 没有就新建,有就打开
O_EXCL - 辅助O_CREAT 没有就新建,有返回-1
O_TRUNC - 没有就新建,有就清空后打开
O_APPEND - 追加方式打开,一般是追加写
返回 可用的文件描述符 最小值,失败返回-1
注: 如果新建文件,需要第三个参数 -- 文件权限
常识:关于文件的操作,有两组信息
1.硬盘上的文件信息,比如文件大小,文件权限,文件的最后修改时间...;
2.内存中的文件描述符信息,比如:描述符权限(O_RDONLY等),文件偏移量...;
read() 和 write()
int read(int fd,void* buf,size_t count)
int write(int fd,void* buf,size_t count)
参数: fd - 文件描述符
buf - 任意类型的首地址
count - 对于read(),count是期望值
对于write(),count是实际值
返回真实的字节数(读/写),失败返回-1
read() 返回 0 代表读完
vi用wq保存退出时,多加一个换行符
练习:
1.员工管理系统 - 新增员工、查询员工信息
新增: 输入员工的信息,把信息保存到文件中,员工信息包括:员工编号、姓名、工资
查询: 把文件中的员工信息读出来并打印出有效信息
-----------------------------------------------------------
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5 struct Data
6 {
7 int id;
8 char name[20];
9 double salary;
10 };
11
12 void add()
13 {
14 struct Data Data;
15 int fd = open("data",O_RDWR|O_CREAT|O_APPEND,0666);
16 if(fd == -1) perror("OPEN"),exit(-1);
17 printf("请输入ID:\n");
18 scanf("%d",&Data.id);
19 printf("请输入姓名:\n");
20 scanf("%s",Data.name);
21 printf("请输入工资:\n");
22 scanf("%lf",&Data.salary);
23 write(fd,&Data,sizeof(Data));
24 close(fd);
25 }
26
27 void query(int id)
28 {
29 struct Data Data;
30 int fd = open("data",O_RDONLY);
31 if(fd == -1) perror("OPEN"),exit(-1);
32 while(read(fd,&Data,sizeof(Data)))
33 {
34 if(Data.id == id)
35 break;
36 }
37 printf("ID:%d\n姓名:%s\n工资:%lg\n",Data.id,Data.name, Data.salary);
38 close(fd);
39 }
40 int main()
41 {
42 int x;
43 printf("输入 1 新增, 2 查询:\n");
44 scanf("%d",&x);
45 if(x==1)
46 {
47 while(x)
48 {
49 add();
50 printf("是否继续输入?(1/0)");
51 scanf("%d",&x);
52 }
53 }
54 else if(x==2)
55 {
56 printf("请输入查询ID:\n");
57 scanf("%d",&x);
58 query(x);
59 }
60 }
-----------------------------------------------------------
2.修改写文件的代码,实现 用cat命令查看时,能显示 可以看懂的信息。比如:
1,zhangfei,12000.000000
思路:sprintf() 只有字符串写入才能看懂
-----------------------------------------------------------
1 #include <stdio.h>
2 #include <unistd.h>
3 #include <stdlib.h>
4 #include <fcntl.h>
5 #include <string.h>
6 struct Emp
7 {
8 int id;
9 char name[20];
10 double sal;
11 };
12 int main()
13 {
14 struct Emp em = {1,"zhangfei",12000.0};
15 int fd = open("data",O_RDWR|O_TRUNC);
16 if(fd == -1) perror("OPEN"),exit(-1);
17 char buf[100] = {};
18 sprintf(buf,"%d,%s,%lf",em.id,em.name,em.sal);
19 write(fd,buf,strlen(buf));
20 close(fd);
21 }
-----------------------------------------------------------
time a.out 可以测试程序运行时间,包括总时间,用户层时间和内核层时间
uc的文件读写函数在用户层是没有缓冲区的,如果频繁读写,需要程序员自定义缓冲区,而标C自身有缓冲区;
在系统中,文件描述符对应一张文件表,文件表中记录了描述符的信息和硬盘上文件的信息,定位硬盘上的文件/目录用i节点。ls -i 可以查看i节点,每张文件表 都有自己的偏移量
函数lseek()可以设定文件的偏移量
-----------------------------------------------------------
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fcntl.h>
4 #include <unistd.h>
5
6 int main()
7 {
8 int fd = open("a.txt",O_RDWR);
9 if(fd == -1) perror("OPEN"),exit(-1);
10 char ch;
11 read(fd,&ch,1); printf("%c\n",ch);//a
12 read(fd,&ch,1); printf("%c\n",ch);//b
13 lseek(fd,3,SEEK_CUR);
14 read(fd,&ch,1); printf("%c\n",ch);//f
15 lseek(fd,0,SEEK_SET);//回到开始
16 write(fd,"1",1);//a -> 1
17 lseek(fd,3,SEEK_SET); write(fd,"2",1);//d -> 2
18 lseek(fd,2,SEEK_CUR); write(fd,"3",1);//g -> 3
19 lseek(fd,-2,SEEK_CUR); write(fd,"4",1);//f -> 4
20 lseek(fd,-2,SEEK_END); write(fd,"5",1);//t -> 5
21 close(fd);
22 }
a.txt = abcdefghijklmnopqrst
经验: lseek()的 whence参数使用SEEK_SET
-----------------------------------------------------------
作业:
实现真实版的用户登陆和注册(文件版)
定义一个用户的结构,包括:用户名、密码、邮箱。读写基本单位是结构
用户注册模块 - 用户输入用户名、密码和邮箱,用追加方式写入文件,打印注册成功或失败
增强版:
1 加入密码确认,输入两次密码,两个字符串相等才能继续输入邮箱
2 加入用户名重复的过滤:如果用户名已经存在,那么告知用户,用户名已经被使用
思路: 写之前先读文件,读入一个数组,数组长度 文件大小/sizeof(结构)
用户登陆 - 读文件 ,读入一个数组,数组长度 文件大小/sizeof(结构)。再让用户输入用户名和密码,比较 用户名和密码都相等,登陆成功,否则登陆失败