目录
回顾C文件接口
写操作
int fputs(const char *s, FILE *stream);将字符串写入文件
[wjy@VM-24-9-centos 27]$ cat myfile.c
#include <stdio.h>
int main()
{
FILE* fp=fopen("./log.txt","w");
// 在当前目录创建文件,打开方式为w
//打开文件成功返回文件指针,失败返回nullptr
if(NULL==fp)
{
perror("fopen");
return 1;
}
int cnt=10;
while(cnt--)
{
const char* msg="hello world\n";
fputs(msg,fp);
}
fclose(fp);
return 0;
}
或者用write写入也可以
write(fd,msg,strlen(msg));//将msg信息写入fd文件
如果用write写入,就要加入写入文件的大小 。在我们写入文件的过程中,我们需要写入\0吗?
不需要,\0作为字符串的结束,只是C的规定。文件关心的是字符串的内容,\0是文件结束的标志位,并非我们需要写入的内容。所以不需要将\0写进去。
读操作
w和r默认都是文本读写,如果要二进制写入是wb和rb
char *fgets(char *s, int size, FILE *stream);向s字符串写入文件,size是文件大小
因为C没有像C++的getline直接从文件读取到显示器上,所以只能用fgets将文件写入字符串,再打印出来。
int main()
{
FILE* fp=fopen("./log.txt","r");//读,读入显示器
if(fp==NULL)
{
perror("fopen");
return 1;
}
char buffer[64];//缓冲区--向缓冲区读入
while(fgets(buffer,sizeof(buffer),fp))//将缓冲区内容打印到显示器上
{
printf("%s",buffer);
}
if(!feof(fp))
printf("fgets quit not normal!\n");
else
printf("fgets quit normal!\n");
}
//显示结果
[wjy@VM-24-9-centos 27]$ ./myfile
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
fgets quit normal!
除了fgets还有read函数
为什么从fd文件中读入buffer缓冲区大小要-1呢?因为文件中的字符串写入的时候就没有写入\0,但是如果要从文件中读取出来还要加\0,但是我们不能读出这个\0,所以到小要-1。
为什么read的返回值是int(是读出字符串大小)?在read的参数列表中已经有了读出字符串大小,那么我们不是已经知道字符串的大小,这不是多此一举吗? 其实并不是,参数列表中的大小是想要读出的大小,而实际可能因为缓冲区大小不够,实际没有想要的大小。所以返回值返回的是实际读出数据的大小。
int fd=open("./log.txt",O_RDONLY);
if(fd<0)
{
perror("open");
}
char buffer[1024];
ssize_t s=read(fd,buffer,sizeof(buffer)-1);
if(s>0)
{
buffer[s]=0;
printf("%s\n",buffer);
}
close(fd);
追加操作
w和a都一样,都要向文件中写入文本。但是w-write在写入之前会把文件都清空,然后再写入。而a-append追加,是在原有文件基础上继续写入文件,不会清空。其他原理都和w一样。
我们将原来文件删除后,再查看,随着每一次的追加写入,log.txt的内容都在增加
int main()
{
FILE* fp=fopen("./log.txt","a");
if(fp==NULL){
perror("fopen");
return 1;
}
const char* msg="hello world\n";
int cnt=3;
while(cnt--)
{
fputs(msg,fp);
}
fclose(fp);
}
//运行结果
[wjy@VM-24-9-centos 27]$ ./myfile
[wjy@VM-24-9-centos 27]$ cat log.txt
hello world
hello world
hello world
[wjy@VM-24-9-centos 27]$ ./myfile
[wjy@VM-24-9-centos 27]$ cat log.txt
hello world
hello world
hello world
hello world
hello world
hello world
stdin & stdout & stderr
如果学习文件操作,只停留在语言层面上,是很难对文件有一个深刻理解的!C程序默认会打开三个输入输出流:stdin,stdout,stderr。这些接口用man手册查看,都是FILE*类型,它是C语言的结构,说明C语言将这三个接口都归类为文件。
stdin:键盘;stdout:显示器;stderr:显示器。
fputs(const char *s, FILE *stream)这个函数,是把第一个字符串s写入到第二个文件流当中的,因为stdout也是FILE*文件类型的,所以也可以将字符串写入到输入输出流中。
下面两张图片中,向stdout中写入内容,再将stdout中内容重定向到log.txt文件,发现文件重定向成功。但是向stderr中写入字符串,再用重定向将内容写到log.txt中,没有把内容写到文件中,字符串依旧显示在显示器上。所以,在linux命令行当中,输出重定向本质上是将stdout内容重定向到文件中。虽然都是向显示器中显示,但是stderr和stdout是不一样的。
fputs向一般文件或硬件设备都能写入!硬件包括键盘、显示器;一般文件如log.txt是在磁盘上的,它的本质也是硬件。
系统文件I/O
我们写的程序最终都是要访问硬件:显示器,键盘,文件(磁盘)这些东西的。那么OS(操作系统就是硬件的管理者)。但是用户/语言,程序,lib不能直接访问硬件,也不能直接访问驱动,也不能直接访问OS。所以,所有的语言上的对“文件”的操作,都必须贯穿OS!
我们知道OS对外界是不公开的,操作系统不相信任何人,如果要访问操作系统,需要通过系统调用接口!
几乎所有的语言fopen,fclose,fread,fwrite,fgets,fputs,fgetc,fputc等底层一定需要使用OS提供的接口调用。所有的语言要在操作系统上跑,一定要用统一的接口。
系统调用接口open
open这个系统调用接口的头文件,以及传参形式。pathname代表要打开的文件;flags代表以什么形式打开文件,有w,r,a等;mode可以设立对应文件的权限信息。就比如ll查看文件信息,-rwxrwxr-x就是mode设置的默认信息。返回值是一个整数,文档中描述:return the new file descriptor, or -1 if an