Linux标准C库 <stdio.h> 对文件的操作

C 标准库 <stdio.h> 网址链接

一、open和fopen区别 概念
二、标准C库 man 手册
三、标准C库 API 代码实现
四、标准C库 写入结构体到文件
五、标准C库 fputc()、fputs()函数 API
六、标准C库 fgetc()、feof() 和 ferror()函数 API

一、open和fopen区别 概念

1. 来源

从来源的角度看,两者能很好的区分开,这也是两者最显而易见的区别:

  • open是UNIX系统调用函数(包括LINUX等),返回的是文件描述符(File Descriptor),它是文件在文件描述符表里的索引。
  • fopen是ANSIC标准中的C语言库函数,在不同的系统中应该调用不同的内核api。返回的是一个指向文件结构的指针。
    PS:从来源来看,两者是有千丝万缕的联系的,毕竟C语言的库函数还是需要调用系统API实现的。

2. 移植性

这一点从上面的来源就可以推断出来,fopen是C标准函数,因此拥有良好的移植性;而open是UNIX系统调用,移植性有限。如windows下相似的功能使用API函数CreateFile

3. 适用范围

  • open返回文件描述符,而文件描述符是UNIX系统下的一个重要概念,UNIX下的一切设备都是以文件的形式操作。如网络套接字、硬件设备等。当然包括操作普通正规文件(Regular File)。
  • fopen是用来操纵普通正规文件(Regular File)的。

4. 文件IO层次

如果从文件IO的角度来看,前者属于低级IO函数,后者属于高级IO函数。
低级和高级的简单区分标准是:谁离系统内核更近。低级文件IO运行在内核态,高级文件IO运行在用户态。

5. 缓冲

  1. 缓冲文件系统
    缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用;当执行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读出需要的数据。执行写文件的操作时,先将数据写入内存“缓冲区”,待内存“缓冲区”装满后再写入文件。由此可以看出,内存“缓冲区”的大小,影响着实际操作外存的次数,内存“缓冲区”越大,则操作外存的次数就少,执行速度就快、效率高。一般来说,文件“缓冲区”的大小随机器 而定。fopen, fclose, fread, fwrite, fgetc, fgets, fputc, fputs, freopen, fseek, ftell, rewind等。
  2. 非缓冲文件系统
    缓冲文件系统是借助文件结构体指针来对文件进行管理,通过文件指针来对文件进行访问,既可以读写字符、字符串、格式化数据,也可以读写二进制数据。非缓冲文件系统依赖于操作系统,通过操作系统的功能对文件进行读写,是系统级的输入输出,它不设文件结构体指针,只能读写二进制文件,但效率高、速度快,由于ANSI标准不再包括非缓冲文件系统,因此建议大家最好不要选择它。open, close, read, write, getc, getchar, putc, putchar等。
    一句话总结一下,就是open无缓冲,fopen有缓冲。前者与read, write等配合使用, 后者与fread,fwrite等配合使用。

使用fopen函数,由于在用户态下就有了缓冲,因此进行文件读写操作的时候就减少了用户态和内核态的切换(切换到内核态调用还是需要调用系统调用API:readwrite);
而使用open函数,在文件读写时则每次都需要进行内核态和用户态的切换;表现为,如果顺序访问文件,fopen系列的函数要比直接调用open系列的函数快;如果随机访问文件则相反。

这样一总结梳理,相信大家对于两个函数及系列函数有了一个更全面清晰的认识,也应该知道在什么场合下使用什么样的函数更合适,效率更高。

Linux下open与fopen的区别

int open(const char *path, int access,int mode)
path 要打开的文件路径和名称

access 访问模式,宏定义和含义如下:                        
         O_RDONLY         1    只读打开                         
         O_WRONLY         2    只写打开                         
         O_RDWR           4    读写打开                     
还可选择以下模式与以上3种基本模式相与:                    
         O_CREAT     0x0100   创建一个文件并打开                
         O_TRUNC     0x0200   打开一个已存在的文件并将文件长度设置为0,其他属性保持         
         O_EXCL      0x0400   未使用                            
         O_APPEND    0x0800   追加打开文件                     
         O_TEXT      0x4000   打开文本文件翻译CR-LF控制字符     
         O_BINARY    0x8000   打开二进制字符,不作CR-LF翻译
mode 该参数仅在access=O_CREAT方式下使用,其取值如下:      
         S_IFMT      0xF000   文件类型掩码                      
         S_IFDIR     0x4000   目录                              
         S_IFIFO     0x1000   FIFO 专用                         
         S_IFCHR     0x2000   字符专用                          
         S_IFBLK     0x3000   块专用                            
         S_IFREG     0x8000   只为0x0000                        
         S_IREAD     0x0100   可读                              
         S_IWRITE    0x0080   可写                              
         S_IEXEC     0x0040   可执行

FILE *fopen(char *filename, char *mode)
filename 文件名称

文件权限

mode 打开模式:                                            
        r   只读方式打开一个文本文件                           
        rb  只读方式打开一个二进制文件                         
        w   只写方式打开一个文本文件                           
        wb  只写方式打开一个二进制文件                         
        a   追加方式打开一个文本文件                           
        ab  追加方式打开一个二进制文件                         
        r+  可读可写方式打开一个文本文件                       
        rb+ 可读可写方式打开一个二进制文件                     
        w+  可读可写方式创建一个文本文件                       
        wb+ 可读可写方式生成一个二进制文件                     
        a+  可读可写追加方式打开一个文本文件                   
        ab+ 可读可写方式追加一个二进制文件

总结

open和fopen的区别
前者属于低级IO,后者是高级IO。 前者返回一个文件描述符,后者返回一个文件指针。
前者无缓冲,后者有缓冲。
前者与 read, write 等配合使用, 后者与 fread, fwrite等配合使用。
后者是在前者的基础上扩充而来的,在大多数情况下,用后者。

二、man 手册

参数定义

*path				文件
*mode				文件权限
FILE *fp			返回值(返回的是文件流)
*ptr				buf
size_t size			类型大小
size_t nmemb		个数
stream				文件FILE索引(哪个文件)

EOF作用:
EOF 本来表示文件末尾,意味着读取结束,但是很多函数在读取出错时也返回 EOF ,
那么当返回 EOF 时,到底是文件读取完毕了还是读取出错了?
我们可以借助 stdio.h 中的两个函数来判断,分别是 feof() 和 ferror()
  1. fopen
SYNOPSIS
       #include <stdio.h>

       FILE *fopen(const char *pathname, const char *mode);
  1. fwrite / fread
SYNOPSIS
       #include <stdio.h>

       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);
  1. fseek
SYNOPSIS
       #include <stdio.h>

       int fseek(FILE *stream, long offset, int whence);
  1. fclose
SYNOPSIS
       #include <stdio.h>

       int fclose(FILE *stream);

三、标准C库 API 代码实现

#include <stdio.h>
#include <string.h>

int main()
{
	FILE *fp;
	char *str = "ga li nian gao !";
	char readBuf[128] = {0};

//	FILE *fopen(const char *pathname, const char *mode);
	fp = fopen("./tan.txt","w+");

//	size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);
	//ptr  buf
	//size sizeof 类型大小
	//nmemb 个数 
	//stream 哪个文件
	fwrite(str,sizeof(char),strlen(str),fp);
	
//	int fseek(FILE *stream, long offset, int whence);
	fseek(fp,0,SEEK_SET);

//	size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
	fread(readBuf,sizeof(char),strlen(str),fp);
	
	printf("read data: %s\n",readBuf);

//	int fclose(FILE *stream);
	fclose(fp);

	return 0;
}

请添加图片描述

read / write 的返回值

size_t fwrite 和 size_t fwrite 返回值与第三个参数(size_t nmemb)有关

int nwrite = fwrite(str,sizeof(char),strlen(str),fp);
int nread = fread(readBuf,sizeof(char),strlen(str),fp);
int nwrite = fwrite(str,sizeof(char)*strlen(str),1,fp);
int nread = fread(readBuf,sizeof(char)*strlen(str),1,fp);

请添加图片描述

int nwrite = fwrite(str,sizeof(char)*strlen(str),1,fp);
int nread = fread(readBuf,sizeof(char)*strlen(str),100,fp);
int nwrite = fwrite(str,sizeof(char)*strlen(str),100,fp);
int nread = fread(readBuf,sizeof(char)*strlen(str),1,fp);

请添加图片描述

四、标准C库 写入结构体到文件

Linux查找文件内容(grep)

  • grep是Linux命令行下常用于查找过滤文本文件内容的命令。最简单的用法是:
  • 如果想忽略大小写,可以用-i参数:
  • 如果想搜索目录里所有文件,包括子目录的话,并且在结果中显示行号,可以用以下命令:
grep 查找内容 文件
grep -i 查找内容 文件
grep -nr 查找内容 *			 

请添加图片描述

基于前面的代码写入一个结构体到文件

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>

struct Test
{
	int a;
	char c;
};

int main()
{
	FILE *fp;

	struct Test data1 = {100,'a'};
	struct Test data2;

	fp = fopen("./file4","w+");

	int n_write = fwrite(&data1,sizeof(struct Test),1,fp);
	
	fseek(fp,0,SEEK_SET);

	int n_read = fread(&data2,sizeof(struct Test),1,fp);

	printf("fread %d,%c\n",data2.a,data2.c);

	fclose(fp);

	return 0;
}

请添加图片描述

五、标准C库 fputc()、fputs()函数 API

请添加图片描述

SYNOPSIS
       #include <stdio.h>

       int fputc(int c, FILE *stream);

       int fputs(const char *s, FILE *stream);

写入字符到文件 代码实现

#include <stdio.h>

int main()
{
	FILE *fp;
	 
	fp = fopen("./test.txt","w+");

//int fputc(int c, FILE *stream);
	fputc('a',fp);

	fclose(fp);
	
	return 0;
}

写入字符串到文件 代码实现

请添加图片描述

  1. fputc()函数实现
#include <stdio.h>
#include <string.h>

int main()
{
	FILE *fp;
	int i;
       	char *str = "ga li nian gao !";
	int length = strlen(str);//先计算出大小,不然后面偏移会影响输出

	fp = fopen("./test.txt","w+");

//int fputc(int c, FILE *stream);
	for(i=0;i<length;i++){
		fputc(*str,fp);
		str++;
	}

	fclose(fp);
	
	return 0;
}
  1. fputs()函数实现
#include <stdio.h>
#include <string.h>

int main()
{
	FILE *fp;
	char *str = "ga li nian gao !";

	fp = fopen("./test.txt","w+");

//int fputs(const char *s, FILE *stream);
	fputs(str,fp);

	fclose(fp);
	
	return 0;
}
fputs("ga li nian gao !\n",fp);

六、标准C库 fgetc()、feof() 和 ferror()函数 API

请添加图片描述请添加图片描述
请添加图片描述

SYNOPSIS
       #include <stdio.h>
       
       int feof(FILE *stream);

	   int ferror(FILE *stream);
       
       int fgetc(FILE *stream);

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

feof()、fgetc()调用

#include <stdio.h>
#include <string.h>

int main()
{
	FILE *fp;
	char c;

	fp = fopen("./test.txt","r");

//	int feof(FILE *stream);
	while(!feof(fp)){// nonezero if reach end of file
//	int fgetc(FILE *stream);	
		c = fgetc(fp);
		printf("%c",c);
	}
	fclose(fp);
	
	return 0;
}

fgetc()、 ferror()调用

#include<stdio.h>
#include <stdlib.h>

int main()
{
    FILE *fp;
    char c;
   
    if( (fp=fopen("./file1","r+")) == NULL ){
        printf("打开文件失败!\n");
        exit(0);
    }
 	//int fgetc(FILE *stream);
    //每次读取一个字节,直到读取完毕
    while( (c=fgetc(fp)) != EOF){
        putchar(c);
    }
    //读取文件成功返回非零值,否则返回零值
    //int ferror ( FILE *fp );
    if(ferror(fp)){
        printf("读取失败\n");
    }else{
        printf("读取成功\n");
    }
    fclose(fp);
    
    return 0;
}

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖喱年糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值