【C语言】文件操作(打开,关闭,写入,读取,指针位置)

文件操作的函数在标准库stdio.h中。

#include <stdio.h>

1、fopen, fclose  打开文件,关闭文件

fopen:打开文件。

fclose:关闭文件。

补充:perror:输出errno对应的错误信息。

fopen:   FILE  *fopen(const char *filename, const char *mode)

参数:filename是字符串(要打开的文件),mode是访问模式。

返回:FILE指针,指向打开的文件。若文件不存在,返回NULL。

注意:

使用fopen打开文件,使用完文件立即用fclose关闭文件。否则会资源泄露、数据丢失、影响其它进程。

打开文件后,FILE指针指向文件在内存的位置。文件内部有位置指针(位置标识符),在指针所在位置读取/写入内容。

fclose:    int fclose(FILE *fp)

参数:fp是已打开的文件。

返回:若成功关闭,返回0。若关闭失败,返回EOF。

EOF是在标准库stdio.h中的宏定义,表示已经到达文件末尾,是个负整数常量。

访问模式 mode
文件模式描述
文本文件r打开一个已有的文本文件,只能读取。
文本文件w

打开一个文本文件,只能从头写入内容。如果文件不存在,则会创建一个新文件。

从文件的开头重新写入内容。相当于每次打开文件都是一个空文件。

文本文件a

打开一个文本文件,只能追加写入内容。如果文件不存在,则会创建一个新文件。

在已有的文件内容中追加内容。

文本文件r+打开一个已有的文本文件,允许读和写。
文本文件w+

打开一个文本文件,允许读和写。如果文件不存在,则会创建一个新文件。

从文件的开头重新写入内容。相当于每次打开文件都是一个空文件。

文本文件a+

打开一个文本文件,允许读取和追加写入。如果文件不存在,则会创建一个新文件。

读取会从文件的开头开始,写入则只能是追加模式。

二进制文件rb打开一个已有的二进制文件,只能读取。
二进制文件wb

打开一个二进制文件,只能从头写入内容。如果文件不存在,则会创建一个新文件。

从文件的开头重新写入内容。相当于每次打开文件都是一个空文件。

二进制文件ab

打开一个二进制文件,只能追加写入内容。如果文件不存在,则会创建一个新文件。

在已有的文件内容中追加内容。

二进制文件rb+打开一个已有的二进制文件,允许读和写。
二进制文件wb+

打开一个二进制文件,允许读和写。如果文件不存在,则会创建一个新文件。

从文件的开头重新写入内容。相当于每次打开文件都是一个空文件。

二进制文件ab+

打开一个二进制文件,允许读取和追加写入内容。如果文件不存在,则会创建一个新文件。

读取会从文件的开头开始,写入则只能是追加模式。

#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("aaa.txt","r");       // 打开文件,(文件aaa.txt不存在)
    printf("file is %s\n", file);      // 若打开的文件不存在,fopen返回NULL
    // 文件具体操作,此处省略
    fclose(file);                      // 关闭文件
    return 0;
}

// 结果:
file is (null)

打开文件时,若发生错误(例如:只读模式下文件不存在),会用标准库errno.h中的全局整数变量errno来记录错误号。

通过标准库string.h中的strerror 获取errno对应的错误信息。 

通过标准库stdio.h中的perror 输出errno对应的错误信息

 perror:    void perror(const char *str)   

参数:字符串(自定义信息,在系统错误信息之前显示)

返回:无。

注意:perror 输出错误信息。 将errno对应的错误信息输出到标准错误(stderr)。

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

int main(void)
{
    FILE *file;
    file = fopen("aaa.txt","r");       // 打开文件 

    printf("%s\n",strerror(errno));    // 若打开的文件不存在,全局变量errno会记录错误号,strerror获取对应错误信息
    if(file == NULL)
    {
        perror("Open file failed");    // perror输出错误信息,将errno对应的错误信息输出到标准输出(stderr)
        return -1;
    }

    fclose(file);                      // 关闭文件
    return 0;
}

// 结果:
No such file or directory
Open file failed: No such file or directory

2、fputc, fputs, fwrite, fprintf  往文件中写入内容

fputc:将一个字符写入文件。

fputs:将字符串写入文件(不包括结束符'\0')。

fwrite:将数组中的数据写入文件

fprintf:将格式化字符串写入文件。

fputc:   int  fputc(int char, FILE  *stream)

参数:char是要写入的一个字符(转为对应的int值来传递),stream是被写入的文件。

返回:被写入的字符。若发生错误,返回EOF,并设置错误标识符。

#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("aa.txt", "w");    // 打开文件,"w"只能写。若追加内容,访问模式用"a"
    // 写入26个大写字母
    for(int c = 65; c < 65+26; c++)
    {
        fputc(c, file);             // 写入一个字符
    }
    
    fclose(file);
    return 0;
}

// 结果:aa.txt
ABCDEFGHIJKLMNOPQRSTUVWXYZ

fputs:   int  fputs(const char *str, FILE  *stream)

参数:str是要写入的字符串,stream是被写入的文件。

返回:非负值。若发生错误,返回EOF。

注意:字符串是以结束符'\0'为终止的字符数组,但结束符'\0'不会被写入文件中。

结束符'\0':NUL,空字符,表示字符串的结束。

#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("aa.txt", "w");
    
    fputs("hello world, good luck", file);              // 写入字符串
    
    fclose(file);
    return 0;
}

// 结果:aa.txt
hello world, good luck

fwrite:    size_t  fwrite(const  void  *ptr, size_t  size,  size_t  nmemb, FILE  *stream)

参数:ptr是要写入的数组(指向数组的指针),size是数组中每个元素的内存大小,nmemb是要写入的元素个数,stream是被写入的文件。

返回:被写入的元素总数。

#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("aa.txt","w"); 
    char s[] = "Have a good day, good luck.";
    // 将数组的数据写入文件
    fwrite(s, sizeof(char), 16, file);          // 写入数组中16个字符
    fputc('\n', file);                          // 写入一个字符:换行符
    fwrite(s, sizeof(char), sizeof(s), file);   // 写入数组中所有字符(包括结束符'\0'即NUL即空字符)

    fclose(file);
    return 0;
}

// 结果: aa.txt
Have a good day,
Have a good day, good luck.

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

参数:stream是被写入的文件。format是要写入的字符串(包括格式化说明符)。

返回:被写入的字符总数。若写入失败,返回负数。

#include <stdio.h>

int main(void)
{
    FILE *file;
    file = fopen("aa.txt","w"); 
    
    fprintf(file, "%s %s\n", "123", "234");              // 格式化输出到文件中
    fprintf(file, "%s %s %s\n", "hello", "good", "luck");

    fclose(file);
    return 0;
}

// 结果: aa.txt
123 234
hello good luck

3、fgetc, fgets, fread, fscanf   读取文件内容

fgetc: 从文件中读取一个字符。

fgets:从文件中读取一行(指定读取最大字符数)。

fread:从文件中读取数组中的数据。

fscanf:从文件中读取格式化输入。

补充:feof:判断是否到达文件末尾。

           ferror:判断是否有错误信息码。

           clearerr:清除文件结束和错误信息码。

fgetc:   int  fgetc(FILE  *stream)

参数:被读取的文件。

返回:读取的字符。若到达文件末尾或发生错误,返回EOF。

补充:feof 判断是否到达文件末尾

 feof:   int feof(FILE  *stream)

参数:stream是要操作的文件。

返回:没有到达文件末尾,返回0。到达文件末尾(碰到文件结束标识符),返回非零值。

#include <stdio.h>

int main(void)
{
    FILE *file;
    char c;
    file = fopen("aa.txt", "r");    // 打开文件。aa.txt内容:Have a good day, good luck!

    while(1)
    {
        c = fgetc(file);           // 读取一个字符     
        if(feof(file))             // 到达文件末尾(即feof返回非零值),退出while循环
        {
            break;
        }
        printf("%c",c);
    }

    fclose(file);                 // 关闭文件
    return 0;
}

// 结果:
Have a good day, good luck!

 若读取时发生错误,可用ferror捕捉错误标识符。用clearerr清除文件结束和错误标识符

 ferror:    int  ferror(FILE  *stream)

参数:stream是要操作的文件。

返回:若设置了错误标识符,返回非零值。若没有错误标识符,返回0。

 clearerr:   void  clearerr(FILE  *stream)

参数:stream是要操作的文件。

返回:无。若参数是无效的stream,则返回-1,并设置errno为EBADF("Bad file descriptor",表示文件描述符无效或不合法)。

#include <stdio.h>

int main(void)
{
    FILE *file;
    char c;
    file = fopen("aa.txt", "w");    // 打开文件。"w"只能写,不能读取
    while(1)
    {
        c = fgetc(file);           // 读取一个字符,若发生错误,会设置错误标识符
        if(ferror(file))           // 判断是否有错误标识符,若非零值则有错误
        {
            printf("Read file failed");
            break;
        } 
        printf("%c",c);
    }
    clearerr(file);                // 清除文件结束和错误标识符

    fclose(file);
    return 0;
}

// 结果:
Read file failed

fgets:    char  *fgets(char *str, int  n, FILE *stream)

参数:str是存储要读取的字符串(指向字符数组的指针),n是读取的字符数(包括空字符),stream是被读取的文件。

返回:相同的str参数(str指向字符数组的指针)。若到达文件末尾或发生错误,返回空指针。

注意:fgets 指定读取最大字符数(包括最后的空字符),若读取到n-1个字符或碰到换行符或到达文件末尾就会停止读取。

#include <stdio.h>

int main(void)
{
    FILE *file;
    char s[16];
    file = fopen("aa.txt", "r");    // 打开文件。aa.txt内容:Have a good day, good luck!

    if(fgets(s, 16, file) != NULL)  // 读取16个字符的字符串(读取15个字符,1个空字符结束字符串)   
    {
        printf("%s", s);
    }
    
    fclose(file);
    return 0; 
}

// 结果:
Have a good day

fread:    size_t  fread(void  *ptr, size_t  size,  size_t  nmemb, FILE  *stream)

参数:ptr是存储读取内容的数组(最小内存大小size*nmemb),size是数组中每个元素的内存大小,nmemb是要读取的元素个数,stream是被读取的文件。

返回:成功读取的元素总数。若元素总数与参数nmemb设置的数不同,则可能发生错误或到达文件末尾。

#include <stdio.h>

int main(void)
{
    FILE *file;
    char s[16];
    file = fopen("aa.txt", "r");        // 打开文件。aa.txt内容:Have a good day, good luck!

    fread(s, sizeof(char), 15, file);   // 读取数组中的15个字符     
    printf("%s", s);

    fclose(file);                       // 关闭文件
    return 0;
}

// 结果:
Have a good day

fscanf:   int  fscanf(FILE  *stream, const char *format,...)

参数:stream是被读取的文件,format是字符串(包括格式化说明符)。

返回:成功匹配和赋值的字符个数。若到达文件末尾或发生错误,返回EOF。

#include <stdio.h>

int main(void)
{
    FILE *file;
    char s1[8], s2[8], s3[8];
    int k;
    file = fopen("aa.txt", "r");                     // 打开文件。aa.txt内容:This year is 2024, good luck!

    fscanf(file, "%s %s %s %d", s1, s2, s3, &k);     // 读取格式化输入(碰到空格就读取结束,读取下一个格式化字符串)   
    printf("%s\n%s\n%s\n%d", s1, s2, s3, k);

    fclose(file);
    return 0;
}

// 结果:
This
year
is  
2024

4、文件内部指针(位置标识符)的当前位置

ftell:获取文件内部指针的当前位置。

rewind:设置文件内部指针的当前位置为文件开头。

fseek:设置文件内部指针的当前位置(开头SEEK_SET,当前位置SEEK_CUR,末尾SEEK_END)。

fgetpos:.获取文件内部指针的当前位置,并写入pos。

fsetpos:设置文件内部指针的位置为给定位置(fgetpos获取的pos值)。

ftell:   long int  ftell(FILE  *stream)

参数:stream是要操作的文件。

返回:文件内部指针的当前值。若发生错误,返回-1L,并设置全局变量errno为正值。

rewind:   void  rewind(FILE  *stream)

参数:stream是要操作的文件。

返回:无。

fseek:     int  fseek(FILE  *stream, long int  offset, int whence)

参数:stream是要操作的文件,offset是相对于参数whence的偏移量,whence是文件内部指针开始偏移的位置(开头SEEK_SET,当前位置SEEK_CUR,末尾SEEK_END)。

返回:0。若发生错误,返回非零值。

fgetpos:   int  fgetpos(FILE  *stream, fpos_t  *pos)

参数:stream是要操作的文件,pos是指向fpos_t对象的指针(fpos_t对象记录文件内部指针当前位置)。

返回:0。若发生错误,返回非零值。

注意:pos指向的对象,其值以内部格式存储,仅供fgetpos和fsetpos使用。

fsetpos:      int  fsetpos(FILE  *stream, const  fpos_t  *pos)

参数:stream是要操作的文件,pos是通过fgetpos获得的位置(指向fpos_t对象的指针)。

返回:0。若发生错误,返回非零值,并设置全局变量errno为正值。

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

int main(void)
{
    FILE *file;
    fpos_t position;
    // "wb"二进制只写模式(写完关闭文件,再次以可读的方式打开文件才能读取。"wb+"模式可边写边读)
    file = fopen("aa.txt", "wb");
    // 若打开文件失败,输出错误信息,并退出程序
    if(file == NULL)
    {
        perror("Open file failed");
        return -1;
    }
    // 往空文件写入内容
    char s1[] = "have a good day ";
    fwrite(s1, sizeof(char), strlen(s1), file);

    fgetpos(file, &position);                    // fgetpos:获取文件内部指针的当前位置,并写入position
    // 继续写入内容
    char s2[] = "good luck ";
    fprintf(file, "%s", s2); 

    fsetpos(file, &position);                    // fsetpos:设置文件内部指针的当前位置为 fgetpos获取的位置
    // 通过fsetpos回到fgetpos获取的位置,写入内容,覆盖原来的内容
    char s3[] = "learn C programming language";
    fputs(s3, file); 

    rewind(file);                                // rewind:设置文件内部指针的当前位置为文件开头
    // 回到开头,写入内容,覆盖原来的内容
    char s4[] = "hello world";
    for(int i = 0; i < strlen(s4); i++)
    {  
        fputc(s4[i], file);
    }

    fseek(file, 0, SEEK_END);                    // fseek:设置文件内部指针的当前位置,此处设为文件末尾

    int length;
    length = ftell(file);                        // ftell:获取文件内部指针的当前位置
    printf("file has %d char\n", length);
    // 关闭文件
    fclose(file);
    
    // 打开文件,只读
    file = fopen("aa.txt", "r");
    int c;
    while(1)                                    // 读取文件所有内容
    {
        c = fgetc(file);                        // 一个字符一个字符读取
        if( feof(file) )                        // 若到达文件末尾,就退出while循环
        {
            break;
        }
        printf("%c",c);
    }
    // 关闭文件
    fclose(file); 

    return 0;
}

// 结果:
file has 44 char
hello world day learn C programming language

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值