一、文件常见的几种打开与读写方式:
FILE *fopen(const char *path, const char *mode);//它是库函数 打开文件
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);//读入数据
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);//fwrite写入数据
ssize_t write(int fd, const void *buf, size_t count);//write写入数据
#include <stdio.h>
extern FILE *stdin;//标准输入
extern FILE *stdout;//标准输出
extern FILE *stderr;//标准错误
pcb.c
1 #include<stdio.h>
2 #include<unistd.h>
3 #include<string.h>
4 int main()
5 {
6 printf("pid: %d,ppid: %d,uid: %d,euid: %d ,gid: \%d, egid: %d\n"\ 7 ,getpid(),getppid(),getuid(),geteuid(),getgid(),getegid());
8 FILE*fp=fopen("./log","w");
9 if(NULL==fp){
10 perror("fopen");
11 return 1;
12 }
13 const char*str="hello,bit!!!\n";
14 int i=0;
15 while(i<10){
16 fwrite(str,strlen(str),1,fp); //linux下一切皆文件,‘\0’不写入文件里,所以不用加1
17 i++;
18 }
19 fclose(fp);
20 return 0;
21 }
makefile
.PHONY:clean
pcb:pcb.o
gcc -g $^ -o $@
%.o:%.c
gcc -c -g $< -o $@
clean:
rm -f *.o main
运行结果:
把内容写进了log文件中并进行了清空
普通用户可以往log里写内容么?
怎样解决呢?
几个标识符的名称:
一个整数最少能传32个标识符 每一个宏占一个比特位
二、文件描述符fd
文件描述符就是一个小整数。默认的3个缺省打开的文件描述符
0:标准输入 键盘
1:标准输出 显示器
2:标准错误 显示器
文件描述符的应用:
14 printf("fd:%d\n",fd);
15 int fd1=open("./mylog1",O_WRONLY|O_CREAT,0644);
16 int fd2=open("./mylog2",O_WRONLY|O_CREAT,0644);
17 printf("fd1:%d\n",fd1);
18 printf("fd2:%d\n",fd2);
文件描述符就是从0开始的小整数。(0-7)
打开文件:
1)file结构体:描述目标文件的结构体(表示一个已经打开的文件对象)
2)让进程和文件关联起来:(进程执行open系统调用)
3)每个进程都有一个指针*files,指向一张表files_struct(包含一个指针数组,每个元素都是一个指向打开文件的指针)本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。
close(0);
close(2);
结论;
文件描述符的分配规则:
从当前的最小的未被分配的文件描述符给你
进程和文件之间的对应关系:
所谓的文件描述符就叫做数组下标
close(1)
FILE里面有一个结构体,里面存在文件描述符
文件指针和文件描述符的区别:
- 文件指针是指针,文件描述符是一个整数
- 文件指针是c语言结构层识别的,文件描述符是系统调用层识别的。
- 文件指针里存在一个结构体,里面存在与之对应的文件描述符。
重定向的原理:
将对应的数组里的内容做个改变。
输出重定向:先把1关闭,再打开文件。
输入重定向:先把0关闭,再打开文件。
追加重定向:
为什么FILE结构体中会存在文件描述符?
系统调用及文件调用
分析:
发现库函数多打印了
为什么printf多打了2次?
fork之前调用完了。当往显示器里写没问题,往文件里写就有问题了*,与写入的类型文件无关;
如果代码无fork,是单进程,会不会与出现这种问题?
不会,因为它只有一个执行流
总结:原因:
文件的写入问题。在fork之前文件已经被写入了文件里,就不可能出现大量打印的问题。(当调用fork时,printf和fwrite里的数据并没有被写入到文件里。)
1)全缓冲问题
2)写时拷贝问题
缓冲方式:
行缓冲:如果这条语句写完包含‘\n’,并刷新到屏幕上
全缓冲:写入数据全写在缓冲区里,知道缓冲区满或进程退出才会刷新到目标文件之中。
- printf的调用是父进程调用的fork,父子进程发生写时拷贝,分别调用printf,所以打两次
- write只打一次说明它没有缓冲区,fwrite底层调用write,说明缓冲区是c库提供的
FILE文件里包含的内容:
- 文件描述符
- 行缓冲