C语言文件读写函数总结

一、字符读写

1、字符写入文件函数 fputc

fputc函数的原型如下:

    int fputc( int c, FILE *fp );

参数说明:
    其中,c是要写入的字节,它虽被定义为整型,但只使用最低位的一字节,fp是文件指针。

fputc的功能:
    将字节c输出至fp所指向的文件。如果成功,位置指针自动后 移1字节的位置,并且返回c;否则返回EOF。

 

2、从文件中读取字符 fgetc

fgetc函数的原型如下:

    int fgetc( FILE *fp );

参数说明:
    其中fp为文件指针。

fgetc的功能:
    从fp所指向的文件中读取一个字节,如果成功则返回读取的字节,位置指针自动后移1字节的位置;否则返回EOF。

 

二、字符串的读写

1、字符串写入文件函数 fputs

fputs函数的原型如下:

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

参数说明:
    其中,s是要写入的字符串,fp是文件指针。

fputs的功能:
    将字符串s输出至fp所指向的文件(不含'\0')。如果成功,位置指针自动后移,函数返回一个非负整数;否则返回EOF。

 

2、从文件中读取字符 fgets

fgets函数的原型如下:

    char *fgets( char *s, int n, FILE *fp );

参数说明:
    其中,s指向待赋值字符串的首地址,n是控制读取个数的参数,fp为文件指针。 

fgets的功能:
    从位置指针开始读取 一行或n-1个字符,并存入s,存储时自动在字符串结尾加上'\0'。如果函数执行成功,位置指针自动后移,
并返回s的值,否则返回NULL。

 

三、块数据读写

所谓块读写,就是读写n块以m个字节为单位的二进制数据,可以是一个字符(一个字符为一字节,则块大小为1*1),可以是一个长度为n字符串(块大小1*n),可以是长度为n的整型数组(整型以4字节算,块大小4*n),也可以是结构体等任意数据类型,并没有什么限制。

1、向文件中写入块数据fwrite

fwrite函数的原型如下:

    size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );

参数说明:
    ptr:指向保存读写数据的内存的指针,它可以指向数组、变量、结构体等。
    size:表示每个数据块的字节数。
    count:表示要读写的数据块的块数。
    fp:表示文件指针。
    理论上,每次读写 size*count 个字节的数据。

fwrite的功能:
    从内存中的ptr指向的地址开始,将连续n*size字节的内容写入fp文件中。该函数的返回值是实际写入的数据块个数。

 

2、从文件中读取块数据fread

fread函数的原型如下:

    size_t fread ( void *ptr, size_t size, size_t count, FILE *fp );
//size_t 是在 stddef.h 头文件中使用 typedef 定义的数据类型,表示无符号整数,也即非负数,常用来表示数量。

参数说明:
    见fwrite

fread的功能:
    从文件fp中,连续读取n*size字节的内容,并存入ptr指向的内存空间。该函数的返回值是实际读入的数据块个数。

 

四、格式化读写

格式化读写函数包括fprintf和fscanf两个函数,它们只用于文本文件的读写,不能用于二进制文件的读写。文本文件与二进制文件的区别下面注意点中有介绍。

1、格式化写入文件fprintf

fprintf函数的原型如下:

    int fprintf( FILE *fp, const char* format, 输出参数1, 输出参数2… );

参数说明:
    其中,fp是文件指针,format为格式控制字符串,输出参数列表为待输出的数据。 

fprintf的功能:
    根据指定的格式(format参数)发送数据(输出参数)到文件fp。

例:

#include <stdio.h>
  
int main()
{
    FILE *fp;
    fp = fopen("a.txt","w");
    int a = 10;
    double f = 11.11;
    fprintf(fp, "%d%lf", a, f);
    fclose(fp);
    return 0;
}

注意:fprintf()按格式输入到流,其用法和printf()相同,不过不是写到控制台,而是写到流罢了。注意的是
返回值为此次操作写入到文件的字节数。如int c =fprintf(fp, "%s %s %d %f", str1,str2, a, b) ;
假设str1:10字节;str2:10字节;a:2字节;b:8字节;则最终c为33,因为写入时不同的数据间自动加入一个空格。

 

2、从文件中格式化读取fscanf

fscanf函数的原型如下:

    int fscanf( FILE *fp,  const char* format, 地址1,地址2… );

函数说明:
    其中,fp是文件指针,format为格式控制字符串,地址列表为输入数据的存放地址。 

fscanf的功能:
    根据指定的格式(format参数)从文件fp中读取数据至内存(地址)。

例:

#include <stdio.h>
  
int main()
{
    FILE *fp;   
    fp = fopen("a.txt","r"); //需要创建a.txt文件,然后写入两个数据,空格隔开
    int i=0;
    double f=0;
    fscanf( fp, "%d%lf", &i, &f );
    fclose(fp);
    printf("%d\n%lf\n",i,f);
    return 0;
}

五、一些注意点

(上面的都是网上抄的,下面的是我自己总结的,大佬们有砖的话轻点拍)

1、fputc和fgetc注意点

fputc 每次只能存一个字节,如果将整型、浮点型等数据类型入文件(因为整型浮点型每个数据都需要好几个字节,由于平台不同不固定,具体自己查不列出),就会造成数据只截取最后一个字节导致数据出错;同理fgetc每次也只能读取一个字节。这时用 fprintf 和 fscanf 函数格式化读写比较合适。

fgetc 每次调用只能获取一个字节,如果是中文字符,utf8 编码会占用三个字节,因此要用 fgets 来读取。当然你不嫌累也可以用 fgetc 读三次,然后拼成一个中文字符。

 

2、fputs和fgets注意点

fgets 有局限性,每次最多只能从文件中读取一行内容,因为 fgets 遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread 函数;相应地写入函数为 fwrite。

 

3、fwrite和fread注意点

fwrite和fread直接读写二进制文本。

Ⅰ、这里有人可能有疑问,二进制文件和文本文件有什么区别?

参考:

1、https://www.zhihu.com/question/19971994

2、https://www.cnblogs.com/zhangjiankun/archive/2011/11/27/2265184.html

        直观上的区别是:文本文件打开后我们可以看懂,而二进制文件打开会是一堆“乱码”。但是,其实所有的文件在计算机中都是二进制,导致“乱码”是因为编码上不同。

        举个例子,比如在代码中的整型数65,用fwrite方式写入文件,我们打开文件时就会惊奇的发现,文件中并不是65,而是一个大写的 'A' 。而我们用fprintf却不会出现这个问题,65还是65。这是为什么呢?

        因为fwrite是直接将数据65写进了文件,而fprintf是将65拆成两个字符,‘6’和‘5’,‘6’和‘5’在ASCII编码表中分别是54和53,于是将54和53写进文件。写进文件后我们再来看打开文件时发生了什么?

        文件软件首先将文件中的数据读进内存,然后再将内存中的数据根据这个文本软件设置的编码格式(比如utf-8)进行解码。来看fwrite写入的文件,文件软件读到 '65' 后去编码表中找到对应数据,是 'A' 然后就将 'A' 输出到屏幕上;再看用fprintf写入的文件,文件软件读到 '54' 和 '53' 后去编码表中找到对应数据,是 '6' 和 '5' ,因此最终我们在屏幕上看到的是65。

        更详细的解释去看我发的参考链接,可能讲的更清楚。

注:上面直观上的区别说法不是很准确。当读写采用不同编码表时就会产生乱码,比如你是以utf-8格式写入文件,然后将文件软件换个编码格式,比如 "GB2312" ,这时再打开也会是乱码,根本原因是相同的字符在不同编码中的编号是不同的,比如 "你" 字,"utf-8" 中的编码为e4 bd a0,而在 "GB2312" 中的编码为 c4 e3,你用e4 bd a0在 "GB2312" 为编码下打开,就会在 "GB2312" 中去找对应的字符,那么当然不会是 "你" 字了,也就会产生乱码。

 

Ⅱ、fopen函数中以文本方式与二进制方式打开文件的区别

参考:https://blog.csdn.net/recsysml/article/details/44195793

a、Windows平台下 
如果以“文本”方式打开文件,当读取文件的时候,系统会将所有的"/r/n"转换成"/n";当写入文件的时候,系统会将"/n"转换成"/r/n"写入。 
如果以"二进制"方式打开文件,则读/写都不会进行这样的转换。 

b、在Unix/Linux平台下

“文本”与“二进制”模式没有区别。

读写二进制文件,在fopen函数中mode的参数要加上“b”,用来告诉函数库打开的文件为二进制文件,而非纯文字文件。不过在POSIX系统,包含Linux下会忽略该字符。

 

Ⅲ、了解了文本方式与二进制方式区别我们来总结一下分别是哪些函数使用

a、文本方式读写:fprintf/fscanf

b、二进制方式读写:fgetc/fputc、fgets/fputs、fread/fwrite

 

另:fwrite/fread与write/read的区别:

https://blog.csdn.net/ljlstart/article/details/49535005

 

4、fprintf和fscanf注意点

fscanf将读取的ascii码转换成二进制放到内存中,效率略低;fgetc fputc 都是按照字节存取,无论文本模式还是二进制模式打开,都按照一个一个字节读取,不存在\r\n问题。

还有一点是很多网站中文转utf-8的编码转换,utf-8编码是错的,它上面其实显示出来的是unicode编码,把我搞混好长时间。

 

 

六、代码实例

附上我的测试实例,有空的话自己打开一个个开关,编译运行看是否符合自己预期

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

typedef struct 
{
    char str1[6];
    char str2[6];
    char str3[6];    
}STRS;


int main()
{
    FILE *fp;
    /*
     * fputc
     */

#if 0
    fp = fopen("a.txt","w");
    //char a[3] = "你";
    //fputc(a[0],fp);
    //fputc(a[1],fp);
    //fputc(a[2],fp);
    int a=33;
    fputc(a,fp);
    fclose(fp);
#endif

    /*
     * fgetc
     */

#if 0 
    fp = fopen("a.txt","r");
    char c1 = fgetc(fp);
    char c2 = fgetc(fp);
    fclose(fp);
    printf("%c\n%c\n",c1,c2);
#endif

    /*
     * fputs
     */
    
#if 0
    fp = fopen("b.txt","w");
    char *s = "你好";
    fputs(s, fp);
    fclose(fp);
#endif

    /*
     * fgets
     */

#if 0
    fp = fopen("b.txt","r");
    STRS Strs;
    STRS *strs = &Strs;
	    
    char hello1[6] = "hello";
    char hello3[6] = {'n','i','h','a','o'};
 
    memset(strs->str1,0,6);
    memcpy(strs->str1,hello1,6);
    memset(strs->str3,0,6);
    memcpy(strs->str3,hello3,6);
    //注意1:fgetc只能获取一位char字符,如果是中文字符,需要占三位char字符,因此要用fgets来读取;
    //注意2:读取的数据的长度要小于等于字符数组长度-1,因为字符串最后要存放'\0'。例如现在str2的长度为6,就会导致strs->str2最后不能加上‘\0’,从而会越界,连带输出str3,最终输出你好hello
    memset(strs->str2,0,6);
    fgets(strs->str2,7,fp);
    
    memset(strs->str3,0,6);
    memcpy(strs->str3,hello3,6);
    
    printf("%s\n",strs->str2);
    fclose(fp);
#endif

    /*
     * fprintf
     */

#if 0
    fp = fopen("c.txt","w");
    int b = 65;
    //double f = 1.11;
    //char s[3] = "你";
    //fprintf(fp, "%s", s);
    fprintf(fp, "%d", b);
    //fprintf(fp, "%d %lf", a, f);
    fclose(fp);
#endif

    /*
     * fscanf
     */

#if 0
    fp = fopen("c.txt","r+"); //需要创建a.txt文件,然后写入两个数据,空格隔开
    //int i=0;
    //double f=0;
    //fscanf( fp, "%d%lf", &i, &f );
    //printf("%d\n%lf\n",i,f);
    char c;
    fscanf( fp, "%c", &c);
    printf("%c\n",c);
    fclose(fp);
    
    fp = fopen("c.txt","r+");
    int fscanf_int;
    fscanf( fp, "%d", &fscanf_int );
    printf("%d",fscanf_int);
    fclose(fp);
#endif
#if 0
    fp = fopen("e.txt","r");
    double a = 0;
    fscanf( fp, "%lf", &a);
    fclose(fp);
    printf("%lf\n",a);
#endif
     
    /*
     * fwrite
     */
    
#if 0
    fp = fopen("e.txt","wb");
    //char array[3] = "你";
    //fwrite(array, sizeof(char), 3, fp);
    //double array[3] = {1.11, 2.22, 3.33};
    //fwrite(array, sizeof(double), 3, fp);
    //double a = 3.14159;
    //fwrite(&a, sizeof(double), 1, fp);
    char a=65;
    fwrite(&a, sizeof(char), 1, fp);
    fclose(fp);
#endif

    /*
     * fread
     */
    
    /*
    fp = fopen("e.txt","rb");
    double array[3];
    fread(array, sizeof(double), 3,fp);
    fclose(fp);
    for(int i=0;i<3;i++)
    {
	printf("%lf\n",array[i]);
    }
    */

    return 0;
}

 

  • 56
    点赞
  • 246
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值