linux入门---重谈文件和c语言文件接口

目录标题

  • 重新讨论文件
  • C语言文件调用函数
    • fopen
    • fclose
    • fprintf
    • fgets
  • 系统调用接口
    • 标记位
    • open
    • write
  • read
  • close

重新讨论文件

第一点:
即使文件的内容为空,该文件也会在磁盘上也会占空间,因为文件不仅仅只有内容还有文件对应的属性,文件的内容会占用空间文件的属性也会占用空间,比如说下面的操作:
linux入门---重谈文件和c语言文件接口_第1张图片

创建了一个文件没有往文件里面写入任何内容,看上去这个文件的大小为0十分的合理,但是实际上这个文件在磁盘上是会占用空间的,只是这里显示的是文件的内容占用空间的大小不包括文件的属性,所以当文件的内容为空时这里显示的大小为0。
第二点:
对文件的操作等于对文件的属性进行操作或者对文件的属性和内容进行操作,因为改变文件的属性不一定会改变文件的内容,但是改变文件的内容一定会改变文件的属性。比如说mycode.c里面的代码如下:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     printf("hello world\n");                                                                                                        
  5     return 0;                                                                                                               
  6 }  

当前该文件的属性如下:
linux入门---重谈文件和c语言文件接口_第2张图片
但是我们将文件的内容进行修改改成下面的形式:

  1 #include<stdio.h>
  2 int main()
  3 {
  4     printf("hello world\n");
  5     printf("hello world\n");                                                                                                        
  6     return 0;                                                                                                               
  7 } 

再查看这个文件的属性时就可以看到此时文件的属性就发生了很多的变化:
linux入门---重谈文件和c语言文件接口_第3张图片
所以这时对文件的操作就是对文件的内容和属性进行操作,当然我们也可以只对文件的属性进行操作,比如说改变文件的拥有者,所属组,以及这些人在文件上的权限等等都是对文件的属性进行的操作:
linux入门---重谈文件和c语言文件接口_第4张图片
这里修改了文件中人的权限,此时文件的内容没有被修改,但是文件的属性被修改了,那么这就是对文件的属性进行操作。
第三点:
使用文件操作时得使用文件路径加文件名的方式以确保唯一性,因为在不同的路径下会存在着同名的不同文件,为了确保唯一性就得使用文件路径加文件名的方式来操作文件,比如说下面的操作,在家目录下创建一个空文件mytest.c
在这里插入图片描述
然后在其他路径下使用另外一个可执行程序来往mytest文件里面写入对应内容,那这里的代码就如下:

  1 #include<stdio.h>  
  2 #include<string.h>
  3 int main()
  4 {
  5     FILE*fd=fopen("/home/xbb/mytest","w");
  6     if(!fd)
  7     {
  8         printf("open error\n");
  			return 1;
  9     }
 10     const char * str="hello world\n";                                                                                               
 11     int count =5;                      
 12     while(count--)                     
 13     {                                  
 14         fwrite(str,strlen(str),1,fd);  
 15     }                                  
 16     fclose(fd);                        
 17     return 0;                                                                                                                 
 18 }    

将这段代码执行一边然后再查看文件的内容就会发现此时的文件中多出来五段话:
linux入门---重谈文件和c语言文件接口_第5张图片
那么这就是路径加文件名的作用他可以帮我们指明确定的文件

第四点:
如果没有指名对应的文件路径,默认是在当前路径进行访问,这里的当前路径就是进程当前的路径,也就是你在哪个路径下执行的文件,那么这个路径就是进程的当前路径。比如说在路径/home/xbb/folder3/下有个名为mycode.c的文件,这个文件的内容为:

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<sys/types.h>
  4 int main()
  5 {
  6     while(1)
  7     {
  8         printf("我的pid为:%d\n",getpid());
  9         sleep(5);
 10     }
 11     return 0;
 12 }       

这个文件生成的可执行程序就是一个死循环在循环里面打印本进程的pid,之前我们讲过在根目录下有个名为proc的文件夹,这个文件夹里面装着许多文件夹,这些文件夹以系统中的各种进程名为名,并装着对应进程的各种信息,比如说下面的图片:
linux入门---重谈文件和c语言文件接口_第6张图片
将上面的代码运行起来就可以看到此时该进程的pid为:
linux入门---重谈文件和c语言文件接口_第7张图片
然后在myproc文件夹里面就会存在一个名为30521的文件夹,进入这个文件夹就可以看到与该进程有关的一些信息:
linux入门---重谈文件和c语言文件接口_第8张图片
此时就会显示两个链接文件,链接文件exe表示的是该进程对应的文件在磁盘中的位置也就是/home/xbb/folder4/mycode,而链接文件cwd表示的意思是该进程的当前路径,我们在folder4文件夹里面执行的这个程序,所以该进程的当前路径就是/home/xbb/folder4,如果我们在路径/home下执行的这个程序,那么该程序的当前路径就是:/home,比如说下面的操作:
linux入门---重谈文件和c语言文件接口_第9张图片
linux入门---重谈文件和c语言文件接口_第10张图片
所以如果你在程序里面对文件进行操作并不带地址的话,就会在当前路径下查找文件创建文件修改文件希望大家能够理解。
第五点:
当我们把fopen,fclose,fwrite等接口写完之后,代码编译之后,形成二进制可执行程序之后如果程序被没有执行,则对应的文件操作是不会被执行的,所以对文件的操作本质上就是进程对文件的操作。
第六点:
文件访问的前提是用户使用了访问文件相关的函数然后程序加载进内存变成进程,在进程中调用函数访问文件,但是这些函数本质上使用的是操作系统提供的接口,所以对文件进行操作得靠用户+进程+操作系统来完成。
第七点:
磁盘上有很多的文件,但是并不是所有的文件都被打开了,所以将文件分为两类一个是被打开的文件,一个是没有被打开的文件,所以文件操作的本质就是进程与被打开文件的关系。

C语言文件调用函数

在谈系统调用接口之前我们先来谈谈c语言里面的文件调用函数。

fopen

操作文件之前首先得打开文件在c语言里面打开文件得使用fopen函数,该函数的介绍如下:
linux入门---重谈文件和c语言文件接口_第11张图片
第一个参数表示要打开文件的文件名,如果文件名没有带路径的话,该函数就会在当前路径下查找并打开这个文件,如果传过来的文件名带了路径的话就会到指定路径下查找并打开这个文件。第二个参数表示的是打开文件的方式,r表示只读也就是只能从文件中读取数据,w表示只写也就是只能往文件中写入数据,a表示的是往文件的后面尾插数据,r+表示读写表示既可以读取文件中的数据也可以往文件里面写入数据但是这种方式不存在出错,w+也表示读写但是以w+形式打开文件不存在创建。以w的形式打开文件如果文件名没有的话会在当前路径下创建文件,而w+形式如果源文件没有的话是不会创建文件,并且w方式打开文件会清空文件中原来的数据,比如说下面的操作:
linux入门---重谈文件和c语言文件接口_第12张图片
mytest文件里面有5行内容,然后再以w的方式打开这个mytest文件并且不往里面写入任何内容,这里的代码如下:

  1 #include<stdio.h>  
  2 #include<string.h>                                             
  3 int main()
  4 {                                    
  5     FILE* fd=fopen("/home/xbb/mytest","w");
  6     if(!fd)                                
  7     {                                      
  8         printf("open fail\n");    
  			return 1;   
  9     }                                
 10     fclose(fd);                      
 11                                      
 12     return 0;                        
 13 } 

执行这段代码然后再查看此文件的内容就可以发现这个文件里面没有任何内容。
linux入门---重谈文件和c语言文件接口_第13张图片
那么这就是w方式打开文件的特性,希望大家能够理解。

fclose

既然有函数能够打开文件那么就会有函数关闭文件,那这里的函数就是fclose函数,该函数的介绍如下:
linux入门---重谈文件和c语言文件接口_第14张图片
这个函数只有一个参数,所以使用这个函数的时候直接将文件打开时创建的那个FILE*变量传给这个函数就可以关闭对应文件了,比如说下面的代码:

  1 #include<stdio.h>  
  2 #include<string.h>                                             
  3 int main()
  4 {                                    
  5     FILE* fd=fopen("/home/xbb/mytest","w");
  6     if(!fd)                                
  7     {                                      
  8         printf("open fail\n"); 
  			return 1;      
  9     }                                
 10     fclose(fd);                      
 11                                      
 12     return 0;                        
 13 } 

fprintf

知道如何打开文件如何关闭文件之后我们就得使用fprintf函数往文件里面写入内容,fprintf函数的参数如下:

int fprintf(FILE *stream, const char *format, ...);

printf函数的参数如下:

int printf(const char *format, ...);

这两个函数的参数区别就在于fprintf函数多了一个文件指针类型的参数,printf函数是将你给的内容输出到屏幕上,那么fprintf函数的第一个参数所代表的意思就是将你给的内容输出到第一个参数所指定的文件里面,比如说下面的代码:

  1 #include<stdio.h>
  2 #include<string.h>
  3 int main()
  4 {
  5     FILE* fd=fopen("/home/xbb/mytest","w");
  6     if(!fd)
  7     {
  8         printf("open fail\n");
  9     }
 10     int a =10;
 11     fprintf(fd,"整型变量a的值为:%d\n",a);
 12     fclose(fd);
 13     return 0;
 14 }  

将这段代码执行之后再查看文件的内容就可以看到此时的文件里面显示了代码中fprintf函数里面的对应信息:
linux入门---重谈文件和c语言文件接口_第15张图片
这就是fprintf函数的作用,你要将内容输出到哪个文件就将哪个文件的FILE指针传给fprintf函数。

fgets

fgets函数可以以行为单位读取打开文件里面的内容,这个函数的参数如下:

       char *fgets(char *s, int size, FILE *stream);

从文件中读取内容之后,程序里面得找个地方存储读取的内容,所以fgets函数的第一个参数就表示读取数据存放的地方,第二个参数size表示缓冲区的大小,第三个参数就表示你要从哪个文件中读取数据。函数读取内容成功之后就会返回参数s,如果函数读到文件的末尾或者读取失败的话就会返回一个空指针:
在这里插入图片描述
那这里大家可以通过下面的代码来看看这个函数的使用

  1 #include<stdio.h>                                                                                                
  2 #include<string.h>                                                                                               
  3 int main()                                                                                                       
  4 {                                                                                                                
  5     FILE* fd=fopen("/home/xbb/mytest","w");                                                                      
  6     if(!fd)                                                                                                      
  7     {                                                                                                            
  8         printf("open fail\n");                                                                                   
  9     }                                                                                                            
 10     int a =5;                                                                                                    
 11     while(a)                                                                                                              
 12     {                                                                                                                     
 13         fprintf(fd,"hello world:%d\n",a--);                                                                               
 14     }                                                                                                                     
 15     fclose(fd);                                                                                                           
 16     fd=fopen("/home/xbb/mytest","r");                                                                                     
 17     if(!fd)                                                                                                               
 18     {                                                                                                                     
 19         printf("open fail\n");                                                                                            
 20     }                                                                                                                     
 21     char buffer[64];                                                                                                      
 22     while(fgets(buffer,sizeof buffer-1,fd)!=NULL)                                                                         
 23     {       
 			buffer[strlen(buffer)-1]=0;                                                                                                               
 24         puts(buffer);                                                                                                     
 25     }                                                                                                                               
 26     return 0;
 27 }  

首先以写的方式往文件里面写入内容,然后再以读的方式将文件里面的内容读取到数组buffer里面,这里大家要注意的一点就是fgets函数读取的是字符串,所以该函数会自动的在读取的内容后面添加一个\0,所以为了保证以后打印内容时不越界访问,我们就得在sizeof后面减一来给\0留个位置,此外puts函数在往屏幕上打印的内容的时候会自动添加\n所以我们得将数组中原有的\n去掉,不然这里显示的效果就会和文件里面的效果不一致,那么这段代码的运行结果如下,文件的内容如下:
linux入门---重谈文件和c语言文件接口_第16张图片
不去掉\n显示的效果如下:
linux入门---重谈文件和c语言文件接口_第17张图片
去掉\n显示的效果如下:
linux入门---重谈文件和c语言文件接口_第18张图片
希望大家能够理解fets函数的使用,他是以行为单位读取文件里面的内容,一直到读到\n位置。

系统调用接口

c语言有文件操作接口,c++有文件操作接口,每个语言都有文件操作借口,并且每个语言额度操作接口都还不一样,所以从语言层面上学习文件操作的成本非常的大,但是文件是在硬盘上的,硬盘是外设,外设是被操作系统管理的,所有人想要访问磁盘都无法绕操作系统,所以尽管不同的函数有着不同的文件访问接口但是这些接口本质上都是调用操作系统提供的文件级别的系统调用接口来访问的文件,而操作系统的接口只有一套,不管库函数再怎么变化,底层是不变额度,所以为了节约学习成本我们就要学习这不变的东西。

标记位

宏喜欢用来作为标记位,标记位的作用就是表明某件事情是否发生,如果发生了就传一个标记位,在c语言中一般以一个整型变量作为标记位,但是如果需要10个标记位的话那就得传10个变量用来表示10件事情已经发生这就有点麻烦,所以在linux操作系统中就选择以一个比特位作为标记位,一个整形变量有32个比特位所以一个整形变量就可以充当32个标记位,所以在创建标记位的时候每一个宏所对应的数值只有一比特位是1其他都为0并且不同标记为里面1的位置不重合。看了这个介绍想必大家还是不大理解这个标记位有什么用怎么用对吧,那接下来通过下面的例子再来理解理解,首先标记位是一个宏,这个宏实际上就是一个数字,并且这个数字对应的二进制位上只有一个是1,所以我们就可以采用这样的形式来创建标记位:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #define ONE (1<<0)                                                                                                                  
  4 #define TWO (1<<1)
  5 #define THREE (1<<2)
  6 int main()
  7 {
  8 
  9     return 0;            
 10 }

这样每个宏对应的数值都只有一个比特位是1,并且彼此1的位置是不重叠的,所以这里我们就可以创建一个函数,这个函数就只有一个参数并且参数的类型是整型,比如说下面的代码:

 	6 void show(int flags)
    7 {
    8                                                                                                                                   
    9 }  

这个函数的功能就是根据函数的不同参数来实现不同的功能,并且这个函数在传参的时候也只能传标记位,比如说下面这样:

   12     show(ONE);
   13     show(TWO);
   14     show(THREE);
   15     show(ONE|TWO);
   16     show(TWO|THREE);
   17     show(ONE|TWO|THREE); 

因为每个标记位中的只有一个比特位是1并且每个标记位的1的位置还不一样,所以将多个标记为通过按位或合并到一起得到的值会有多个1,但是每个1所代表的意思是不同的,所以在函数里面就可以使用多个if语句加按位与来判断传过来的参数是否有指定的功能,比如说下面的代码:

  6 void show(int flags)  
  7 {  
  8     if(flags&ONE)  
  9     {  
 10         printf("功能ONE\n");
 11     }
 12     if(flags&TWO)
 13     {
 14         printf("功能TWO\n");
 15     }
 16     if(flags&THREE)
 17     {
 18         printf("功能THREE\n");                                                                                                      
 19     }                                                                                                                           
 20 }  

比如说ONE的二进制为001,TWO的二进制为010,THREE的二进制为100,所以ONE|TWO的值就是011,ONE|THREE的值就是101,在show函数里面if语句的判断条件为flags&ONE所以只要你传过来的参数里面有标识符ONE那么这个if语句里面的内容就会被执行,如果传过来的标识符里面没有ONE的话那么不管有多少个其他的标识符,这个if语句的内容都不会执行,比如说TWO|THREE得到的值为011,而ONE的值为100,所以ONE&flags的值就等于ONE&TWO|THREE等于0,那么这就是标识符的作用,那这里完整的代码就如下:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #define ONE (1<<0)
  4 #define TWO (1<<1)
  5 #define THREE (1<<2)
  6 void show(int flags)
  7 {
  8     if(flags&ONE)
  9     {
 10         printf("功能ONE\n");
 11     }
 12     if(flags&TWO)
 13     {
 14         printf("功能TWO\n");
 15     }
 16     if(flags&THREE)
 17     {                                                                               
 18         printf("功能THREE\n");                       
 19     }                                
 20 }                 
 21 int main()                                     
 22 {                                   
 23     show(ONE);           
 24     show(TWO);
 25     show(THREE);
 26     show(ONE|TWO);
 27     show(TWO|THREE);
 28     show(ONE|TWO|THREE);
 29     return 0;                                                                                                                       
 30 }

那么这段代码的执行结果如下:
linux入门---重谈文件和c语言文件接口_第19张图片
那么这就是标记位的作用希望大家能够理解。

open

c语言里面是通过函数fopen来以各种不同的形式打开文件,其实fopen函数是通过对系统调用接口open函数进行封装来实现的,我们来看看open函数的介绍:
linux入门---重谈文件和c语言文件接口_第20张图片
这个函数有两种不同的参数形式,第一个参数pathname表示文件名,第二个参数flags就是标志位,第三个参数mode表示文件的权限。其中第一个参数pathname可以添加路径也可以不添加路径,不添加路径的话该函数就会在当前路径下查找文件。O_RDONLY表示只读标记符,O_WRONLY表示只写标记符,那这个是不是跟c语言的r和w相似呢?我们可以通过下面的例子来证明一下两者的区别:首先c语言中的w只读有两个特性:1.如果源文件存在内容的话那么以只读方式打开文件的话,会将源文件的内容清空。2.如果打开的文件不存在的话,那么fopen函数会自己创建一个函数我们来看看open函数的只读有没有上述的功能比如说下面的操作:在当前路径下创建一个文件,并往文件里面输入一些内容:
linux入门---重谈文件和c语言文件接口_第21张图片
然后再在mycode.c文件里面写入下面的代码:

  1 #include<stdio.h>  
  2 #include<sys/types.h>                                                     
  3 #include<sys/stat.h>  
  4 #include<unistd.h>                                                                                                                  
  5 #include<fcntl.h>                       
  6 int main()                              
  7 {                                       
  8     int fd = open("mytest",O_WRONLY);   
  9     close(fd);                          
 10     return 0;                           
 11 }   

将这段代码运行起来然后再查看文件mytest的内容时就会发现这里并没有将源文件的内容清空:
linux入门---重谈文件和c语言文件接口_第22张图片
并且我们将mytest文件删除再执行上面的代码就可以发现,这里的只写在文件不存在的情况下是不会自动创建文件的:
linux入门---重谈文件和c语言文件接口_第23张图片
那么这就证明open的只读和fopen的只读是不一样,但是fopen是基于open实现的那这又是如何做到的呢?方法很简单open函数还有两个标记位:O_CREAT O_TRUNC。其中O_CREAT的作用就是当文件不存在时会自动创建一个文件,O_TRUNC的作用就是当源文件中存在内容时会将文件的内容进行清空,所以当我们使用c语言的fopen函数以w只读的形式打开文件时,在底层就会调用open函数并以O_CREAT |O_TRUNC|O_WRONLY作为标记位进行传参,比如说下面的代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 int main()
  7 {
  8     int fd = open("mytest",O_WRONLY|O_CREAT|O_TRUNC);
  9     close(fd);
 10     return 0;
 11 } 

将这段代码运行一下就可以看到之前的文件中没有mytest文件,但是这段代码执行一边之后就会自动创建一个mytest文件:
linux入门---重谈文件和c语言文件接口_第24张图片
但是这个文件看上去有点点不对劲,为什么这个文件会是红色的呢?原因很简单因为此时的文件里面都是乱码无法正常的使用,造成这种现象的原因是因为在创建文件的时候没有给对应的权限,也就是遗漏了该函数的第三个参数,当使用open函数创建文件时得使用第三个参数给创建的文件一个起始权限,当使用open函数却不需要创建文件时则不需要第三个参数,所以将乱码文件删除并修改对应的代码再执行以下就可以看到这里生成了一个正常的文件:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 int main()
  7 {
  8     int fd = open("mytest",O_WRONLY|O_CREAT|O_TRUNC,0666);                                                                           
  9     close(fd);
 10     return 0;
 11 }

linux入门---重谈文件和c语言文件接口_第25张图片
给的起始权限是0666,但是这里创建出来的权限确实0664,那出现这样的原因这里创建的文件也遵循umask的原则,所以这里要是想让创建的文件就是我们给的起始权限的话就可以使用umask函数:
linux入门---重谈文件和c语言文件接口_第26张图片
这个函数可以帮我们在程序里面修改umask值,该函数的参数就是修改后的umask的值,比如说下面的代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 int main()
  7 {
  8     umask(0);                                                                                                                       
  9     int fd = open("mytest",O_WRONLY|O_CREAT|O_TRUNC,0666);                                                        
 10     close(fd);                                                                                                    
 11     return 0;                                                                                                     
 12 }  

将之前的文件删除,再执行一下上面的代码就可以看到这里创建出来的文件的权限就是0666
linux入门---重谈文件和c语言文件接口_第27张图片
但是程序中调用的umask函数不会影响命令行的umask值:
在这里插入图片描述
这里大家要注意一点:使用open函数打开文件时open函数会返回一个整数,这个整数就是文件描述符,在其他函数里面就可以根据这个文件描述符来确定要写入的文件,如果open返回的值为负数的话就表明此时文件打开失败,比如说下面的代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 int main()
  7 {
  8     umask(0);
  9     int fd = open("mytest",O_WRONLY|O_TRUNC);
 10     printf("fd的值为:%d\n",fd);                                                                                                      
 11     close(fd);           
 12     return 0;            
 13 } 

这段代码的执行结果如下:
在这里插入图片描述
我们可以看到此时打印的文件描述符为3,在后面的程序就可以使用这个文件描述符3来代表要被操作的文件mytest。

write

将一个文件以写的打开之后就可以往这个文件里面写入内容,那么这里的写入就得用到write函数,该函数的参数如下:
在这里插入图片描述
第一个参数表示要将内容写入哪个文件,第二个参数表示写入文件的内容来自于哪个缓冲区,这个指针会指向空间开始的位置,并且指针的类型为void说明不管你要写入的数据类型是什么样的这个函数都可以将数据写到文件里面,就是因为在计算机看来所有的数据全部都是二进制,我们平时说的二进制数据和文本数据只不过语言进行的封装罢了,所以这个参数为void就可以了,第三个参数表示写入文件的内容有多少个字节,当这个函数执行完之后就会返回实际写入文件的字节个数。比如说下面的代码:

  1 #include<stdio.h>                                                                                                           
  2 #include<sys/types.h>                                                     
  3 #include<sys/stat.h>  
  4 #include<unistd.h>  
  5 #include<fcntl.h>  
  6 #include<string.h>                                                                                                                  
  7 int main()                             
  8 {                                      
  9     umask(0);                                               
 10     int fd = open("mytest",O_WRONLY|O_TRUNC|O_CREAT,0666);  
 11     if(fd<0)                           
 12     {                                  
 13         perror("open");                
 14     }                                  
 15     int cnt=5;                         
 16     char outbuffer[64];                
 17     while(cnt)                         
 18     {                                              
 19         sprintf(outbuffer,"%s:%d\n","hello",cnt--);  
 20         write(fd,outbuffer,strlen(outbuffer)+1);  
 21     }                                  
 22     close(fd);                         
 23     return 0;                          
 24 }  

这段代码的运行结果如下:
linux入门---重谈文件和c语言文件接口_第28张图片
我们可以看到这段代码执行的结果以及显示的文本信息确实是符合预期的,但是大家打开mytest文件却会发现异常
linux入门---重谈文件和c语言文件接口_第29张图片
这里出现了一些乱码这是为什么呢?原因很简单上面的代码在往文件里面写入内容时写入的字节个数是strlen(outbuffer)+1就好比outbuffer中有一段字符串abcde\n,这个字符串的长度为6大小为6个字节而我们却想往文本里面写入7个字节的内容,所以当函数写入的时候就会自动的在字符串后面添加上一个\0来补齐这7个字节的大小,我们之所以这么干是因为在c语言当中字符串是以\0作为结尾的,如果一个字符串的末尾不存在\0的话就很容易出现问题,所以这里加1是为了防止出现c语言里面的一些越界访问的错误,可是字符串以\0结尾是c语言规定的和文件有关系吗?答案是没关系的,文件中的字符串不是以\0结尾的往文件中写入的时候只需要写入字符串的有效内容就可以了,除非你就像往文件中写入\0不然不要在这里的第三个参数+1,把后面的+1去掉再运行一下代码看看文件的内容如何:
linux入门---重谈文件和c语言文件接口_第30张图片
这里就没有再显示乱码了,这里是往文件中写入内容的操作,如果想要往文件的尾部插入内容的话就得对open函数里面的标记位进行修改,将O_TRUNC去掉并添加O_APPEND然后将输入文件的内容修改一下比如说下面的代码:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 #include<string.h>
  7 int main()
  8 {
  9        umask(0);                                               
 10       int fd = open("mytest",O_WRONLY|O_APPEND|O_CREAT,0666);  
 11       if(fd<0)                           
 12       {                                  
 13           perror("open");                
 14       }                                  
 15       int cnt=4;                         
 16       char outbuffer[64];                
 17       while(cnt)                         
 18       {                                                                                                                             
 19           sprintf(outbuffer,"%s:%d\n","AAAA",cnt--);  
 20           write(fd,outbuffer,strlen(outbuffer));                                                 
 21       }                                                                                          
 22       close(fd);                                                                                 
 23       return 0;                                                                                  
 24 } 

再执行一下这段代码并查看文件的内容就可以发现此时文件的后面又多了一些内容:
linux入门---重谈文件和c语言文件接口_第31张图片
所以标记位O_WRONLY|O_APPEND|O_CREAT组合到一起就是c语言中fopen中a的功能希望大家能够理解。

read

既然可以将缓冲区(数组)里面的内容通过write函数输出到文件里面,那么这里也可以通过read函数读取文件里面的内容并放到缓冲区里面,read函数的参数如下:
在这里插入图片描述
与write函数相似,第一个参数fd表示要读取哪个文件的内容,第二个参数buf表示将读取的内容放入程序的哪个缓冲区中,第三个参数表示你要读取多少个字节的内容。read函数的返回值表示如果读取成功了就返回读取的字符个数,如果读取失败了或者刚开始读就遇到文件结尾了就会返回0,read函数的第二个参数类型是void*,表明read函数在读取内容的时候也没有数据类型的概念,不管文件里面装的是图片还是视频还是一些文本数据等等,它读的都是二进制数据,这些数据具体如何处理那都是使用者自己决定的比如说下面的操作:首先以读的方式打开文件并记录open函数的返回值,如果返回值小于0则表示文件打开失败,如果读取成功了就创建一个缓冲区用来记录读取的数据:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 #include<string.h>
  7 int main()
  8 {                                                                                     
  9       int fd = open("mytest",O_RDONLY);  
 10       if(fd<0)                           
 11       {                                  
 12           perror("open");                
 13       }                                
 14       char buffer[1024];                                                                                                            
 15       close(fd);                                                                                                  
 16       return 0;                                                                                                   
 17 }   

然后使用read函数读取文本中的数据,因为这里采用的是系统提供的函数读取数据,并且我们想让数据以字符串的形式放入到数组里面,所以read函数里面的读取字符的个数得是sizeof(buffer)-1留下来一个空间以免缓冲区满了装不下\0,读取玩数据之后就要在缓冲区的有效内容的后面手动添加一个\0用来表示此时的数据内容是字符串,那这里完整的代码就如下:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<sys/stat.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 #include<string.h>
  7 int main()
  8 {
  9       int fd = open("mytest",O_RDONLY);
 10       if(fd<0)
 11       {
 12           perror("open");
 13           return 1;
 14       }                                
 15       char buffer[1024];
 16       ssize_t size=read(fd,buffer,sizeof(buffer)-1);
 17       if(size>0)
 18       {
 19           buffer[size]=0;
 20       }
 21       printf("%s\n",buffer);                                                                                                        
 22       close(fd);
 23       return 0;                                                                                                                  
 24 } 

mytest文件里面的内容如下:
linux入门---重谈文件和c语言文件接口_第32张图片
所以这段代码的执行结果如下:
linux入门---重谈文件和c语言文件接口_第33张图片
那么这就是read函数的作用,希望大家能够理解。

close

通过上面的代码大家也能够知道close函数就是用来关闭open函数打开的文件的,这个函数的参数如下:
在这里插入图片描述
很简单将文件描述符传给close函数就行了,这里就不说了,看了上面的内容想必大家能够知道一件事就是c语言里面对文件操作的函数:fopen fclose fwrite fread fseek函数在底层其实都是用操作系统提供的接口实现的,这些函数与open close write read lseek函数一一对应,所以我们将底层的函数学会就行,那么这就是本篇文章的全部内容希望大家能够理解。

你可能感兴趣的:(linux入门,linux,c语言,c++)