文件= 内容+属性
对应文件的操作,对内容的操作,对属性的操作
当文件没有被操作的时候,一般在磁盘中
当对文件进行操作的时候,一般在内存中,因为冯诺依曼体系规定
当我们对文件进行操作的时候,文件需要提前加载到内存中,提前加载的是属性
当我们对文件进行操作的时候,文件需要提前加载到内存中,不只有你在load,内存中一定存在大量的不同文件属性
结论:文件被打开,OS要为被打开的文件,创建对应的内核数据结构,struct file结构体 ,该结构体包含各种属性,各种链接关系
FILE *fopen(const char *path, const char *mode);
第一个参数为 打开文件对应的路径
第二个参数为 打开文件对应的权限
如果打开成功,返回FILE指针,否则返回NULL
创建myfile.c文件
E>#include<stdio.h>
#define LOG "log.txt"
E>int main()
{
FILE*fp= fopen(LOG,"w");
//默认写方式 打开文件,如果文件不存在,就创建它
if(fp==NULL)
{
perror("fopen");//报错
return 1;
}
fclose(fp); //关闭文件
return 0;
}
int fputs(const char *s, FILE *stream);
你想要写的字符串,写入特定的流当中,成功返回字符串字符个数,失败返回-1
#include
#define LOG "log.txt"
int main()
{
FILE*fp= fopen(LOG,"w");
//默认写方式 打开文件,如果文件不存在,就创建它
if(fp==NULL)
{
perror("fopen");//报错
return 1;
}
//进行文件操作
const char*msg="bbb\n";
fputs(msg,fp);
fclose(fp); //关闭文件
return 0;
}
将msg字符串中的数据写入fp流中
int fprintf(FILE *stream, const char *format, …);
指定文件流,向文件打印
指定文件流fp,而fp打开的文件为log.txt,所以将msg数据打印到log.txt文件中
因为Linux中一切皆文件,所以也可以传入stdout(标准输出流)中,stdout也对应一个文件,即显示器文件
运行可执行程序,结果显示到显示器了
int snprintf(char *str, size_t size, const char *format, …);
通过格式化流的方式,把字符串信息自定义格式化到字符串缓冲区中,并规定大小
将msg中的数据打印到buffer字符串中,同时使用fputs将buffer中的数据写入刚刚打开的文件log.txt中
追加,不会清空文件,而是每一次写入都是从文件尾部写入的
修改myfile.c文件内容
#include
#define LOG "log.txt"
int main()
{
FILE*fp= fopen(LOG,"a");
//默认写方式 打开文件,如果文件不存在,就创建它
if(fp==NULL)
{
perror("fopen");//报错
return 1;
}
//进行文件操作
const char*msg="bbb\n";
int cnt=1;
while(cnt)
{
fputs(msg,fp);
cnt--;
}
fclose(fp); //关闭文件
return 0;
}
多次运行可执行程序,发现可追加
char *fgets(char *s, int size, FILE *stream);
从特定的文件流中按行所取对应的文件,将读到的内容放到缓冲区中
修改myfile.c文件内容
#include
#define LOG "log.txt"
int main()
{
FILE*fp= fopen(LOG,"r");
if(fp==NULL)
{
perror("fopen");//报错
return 1;
}
//进行文件操作
while(1)
{
char line[128];
if(fgets(line,sizeof(line),fp)==NULL)
break;
else
{
printf("%s",line);
}
}
fclose(fp); //关闭文件
return 0;
}
从fp中读取到line中,如果当前读取返回NULL说明读取失败 ,返回break
此时运行可执行程序,即可看到对应文件中的内容
#include
#include
#include
int open(const char *pathname, int flags);
第一个参数代表 文件路径+文件名
第二个参数 代表 文件对应的选项(选项的问题后面会提)
如果打开成功了,就会返回新的文件描述符,如果打开失败,返回 -1
1. 我们怎么做
通过写一个 函数 若 int XXX (int flag) ,传递参数flag flag=1/2/3 ,将flag进行赋值
2. 系统怎么做
操作系统存在系统调用接口 int YYY (int flag),flag作为一个整数,有32个比特位,可以用一个比特位表示一个标志位
,一个int 就可以同时传递至少32个标记位
此时的flag 就可以看作数据类型 位图 看待
创建test.c文件
#include
//分别代表从右向左的每个比特位
#define ONE 0x1
#define TWO 0x2
#define THREE 0x4
#define FOUR 0x8
void print(int flag)
{
if(flag & ONE )
printf("hello 1\n");//充当函数的不同行为
if(flag & TWO)
printf("hello 2\n");
if(flag & THREE)
printf("hello 3\n");
if (flag & FOUR)
printf("hello 4\n");
}
int main()
{
printf("-------------------------------------\n");
print(ONE); //打印one
printf("-------------------------------------\n");
print(ONE|TWO); //打印one two
printf("-------------------------------------\n");
print (ONE|TWO|THREE);//打印 one two three
printf("-------------------------------------\n");
print (ONE|TWO|THREE|FOUR); //打印 one two three four
printf("-------------------------------------\n");
return 0;
}
通过整数flag 一次传递多个标志位
0000 0000
将最后的四个比特位通过宏的方式分别记录下来
再与flag 按位与 ,若为真,则说明传递的flag 是 这4个比特位中的其中一个
执行可执行程序,此时分别打印出了 one two three four的运行结果
类比上述 open的第二个参数flag ,存在多个标志位,同通过宏来实现,每一个标志位都代表不同的值
在myfile.c文件中重新输入代码
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
int fd=open(LOG, O_WRONLY| O_CREAT);//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
close(fd); //关闭文件
return 0;
}
运行可执行程序,发现
假设log.txt文件不存在,通过创建文件并打开文件,发现新文件的权限不正常
因为在Linux中创建一个文件需要有对应的权限的
int open(const char *pathname, int flags, mode_t mode);
所以在文件不存在时,一般采用有三个参数接口的open
mode代表权限
修改myfile.c文件的内容
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
E> printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
close(fd); //关闭文件
return 0;
}
0666 :拥有者 所属组 other都有读写权限
此时log.txt文件拥有正常的权限
但是输入的是666 ,显示的却是664,即other没有写权限
因为创建一个文件时,默认权限受到umask的影响
使用 man 2 umask
查看
#include
#include
mode_t umask(mode_t mask);
可以影响当前进程启动时,属于自己的umask,采取就近原则,因为自己设置离的更近所以使用自己设置的umask
而不是系统的umask
修改myfile.c文件的内容
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
close(fd); //关闭文件
return 0;
}
使用umask (0) 将权限掩码设置成0
此时log.txt文件的权限为 666
通过 man 2 write
查看文件写入接口
ssize_t write(int fd, const void *buf, size_t count);
fd代表文件描述符
buf代表 缓冲区
count代表 缓冲区大小
write将缓冲区的count大小的数据写入 fd中
返回值代表实际写入多少字节
修改myfile.c文件内容
include<sys/types.h>
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
const char* msg="hello world";
int cnt=5;
while(cnt)
{
char line[128];
snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中
write(fd,line,strlen(line)+1);//将line写入fd中
cnt--;
}
close(fd); //关闭文件
return 0;
}
若 strlen(line)+1 ,则打开log.txt文件时发现出现乱码,因为数字0在ASCII表中属于不可显示字符
所以为了不出现乱码,所以strlen(line) 不应该+1,因为\0是c语言的规定,不是文件的规定
修改myfile.c文件内容
#include
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
const char* msg="hello world";
int cnt=5;
while(cnt)
{
char line[128];
snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中
write(fd,line,strlen(line));//将line写入fd中 strlen不要+1
cnt--;
}
close(fd); //关闭文件
return 0;
}
此时strlen不加1
修改myfile.c文件内容,msg和cnt的数据内容
#include
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG, O_WRONLY| O_CREAT,0666);//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
const char* msg="aaaaa";
int cnt=1;
while(cnt)
{
char line[128];
snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中
write(fd,line,strlen(line));//将line写入fd中 strlen不要+1
cnt--;
}
close(fd); //关闭文件
return 0;
}
O_WRONLY | O_CREAT 默认不会对原始文件清空
O_TRUNC : 将文件做清空
修改myfile.c文件内容
#include
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG, O_WRONLY| O_CREAT| O_TRUNC,0666 );//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
const char* msg="aaaaa";
int cnt=1; while(cnt)
{
char line[128];
snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中
write(fd,line,strlen(line));//将line写入fd中 strlen不要+1
cnt--;
}
close(fd); //关闭文件
return 0;
}
此时再次调用log.txt文件,就会将之前文件中内容清空’
O_APPEND 追加
O_WRONLY: 以写方式打开文件
O_WRONLY | O_APPEND | O_CREAT 若文件存在就以写的方式追加,若文件不存在则创建
修改myfile.c文件内容
#include
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG,O_WRONLY | O_CREAT | O_APPEND ,0666 );//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
const char* msg="bbb"; int cnt=1; while(cnt)
{
char line[128];
snprintf(line,sizeof(line),"%s,%d\n",msg,cnt);//将msg和cnt写入line缓冲区中
write(fd,line,strlen(line));//将line写入fd中 strlen不要+1
cnt--;
}
close(fd); //关闭文件
return 0;
}
此时重复运行可执行程序,打开log.txt文件 ,发现可以追加
O_RDONLY : 读取
输入 man 2 read
ssize_t read(int fd, void *buf, size_t count);
从文件描述符fd中将我们想要的数据,按照数据块的方式读取出来
返回值代表多少字节,读取到文件结尾为0,失败为-1
#include
#include
#include
#include
#include
#include
#include
#define LOG "log.txt"
int main()
{
umask (0);//将权限掩码设置成0
int fd=open(LOG, O_RDONLY );//打开一个文件,若文件不存在则重新创建一个
if(fd==-1)//说明打开失败
{
printf("fd:%d,errno:%d,errstring:%s\n",fd,errno,strerror(errno));//打印出错误信息
}
else
printf("fd :%d\n", fd);
char buffer[1024];
ssize_t n= read(fd,buffer,sizeof(buffer)-1);//使用系统接口来进行IO的时候,一定要注意\0的问题
if(n>0)//成功了,实际读到了多少字节
{
buffer[n]='\0';
printf("%s\n",buffer);
}
close(fd); //关闭文件
return 0;
}
运行可执行程序,可以直接读取到数据
操作系统不相信任何用户,所以操作系统给用户提供系统调用
程序员调用库的接口,而库的接口必定要调用系统调用
打开文件的本质是文件相关的内容加载到内存里
把数据触发从磁盘到内存
把数据从自己的程序写入硬盘上,一定会涉及到对硬件的访问
用户不能使用c/c++库绕过操作系统去访问
软硬件各种资源属于操作系统的,操作系统是硬件的管理者