C语言读写文件的库函数

一、背景知识

       C语言支持文件读写,提供二进制和文本两种方式来读写文件。

 

二、具体使用

  (一)引入输入输出库

#include<stdio.h>

 


  (二)明白文件类型

      1、主要定义

typedef struct _iobuf {
    char *_ptr; // 文件输入的下一个位置
    int _cnt;  // 当前缓冲区的相对位置
    char *_base; // 文件初始位置
    int _flag;  // 文件标志
    int _file;   // 文件有效性
    int _charbuf; // 缓冲区是否可读取
    int _bufsiz;  // 缓冲区字节数
    char *_tmpfname; // 临时文件名
} FILE;

 

   定义指针:

      FILE* 变量名;

   案例:

FILE* fp;

     2、作用

      封装文件的一些参数,用来代表一个文件。


   (三)打开文件

         使用fopen()打开文件。

         定义如下:

  FILE*  fp = fopen(char* path,  char* mode)
​
  1)参数含义:
  path: 字符串指针类型,代表文件的路径,例如"D:/a.txt"
    
  mode: 字符串指针类型,指的用字母来代表当前是读、写、追加里面的哪种模式。
       常用取值:
          r   代表使用文本只读;如果文件不存在会打开失败。
          w   代表使用文本只写;如果文件不存在会创建新文件,如果文件存在会清空以前的内容;
          a   代表追加的方式写入;如果不存在文件会创建新文件,并且文件指针指向末尾;不会清空文件内容;
          r+  代表以支持读取、写入的方式打开文件;如果文件不存在,会打开失败;
          w+  代表以文本读取,写入的方式打开;不存在会创建新文件;存在文件会清空文件内容;
          a+  代表支持添加的写入、读取;如果文件不存在,会创建新文件;
              
          rb   代表只读取二进制文件
          wb   代表只写入二进制文件
          ab   代表追加二进制文件
          r+b  代表以读取、写入的方式操作二进制文件
          w+b  代表以写入、读取的方式操作二进制文件
          a+b  代表追加的方式写入二进制文件,同时支持读取;
​
 2)返回值:
    如果打开成功,返回不为空的FILE*文件指针;
    如果打开失败,返回NULL,把错误代码设置在errno中。

     案例:

// 用只读模式打开文本文件 D:/m.txt
FILE* fp = fopen("D:/m.txt", "r");
​

   (四)读写文本文件

        1、读取单个字符

        定义如下:

int fgetc(FILE* fp)
​
1)参数:
   fp: 是FILE*类型,代表读取的那个文件指针;
   
2)返回值(int类型):
   如果不为EOF,代表是字符的ASCII码;
   如果为EOF,代表文件读到末尾或者出现错误;

     案例:

// 从fp文件指针代表的文件中读取一个字符
int c = fgetc(fp);
​
// 打印该字符
printf("读取的字符是:%c \n", c);

    2、写入单个字符

     定义如下:

​
int fputc(char c, FILE* fp)
​
1)参数:
   c   :  char类型,被写入的字符变量;
   fp  :  FILE*类型,代表目标写入的文件指针;
   
2)返回值(int类型):
   如果是EOF,代表写入失败;
   如果等于传入的char参数,代表写入成功。
   

     案例:

// 定义一个字符
char temp = 'a';
​
// 写入文件指针fp代表的文件中;
int result = fputc(temp, fp);

     3、写入一行字符

       写入字符串后会自动换行。

 

      函数定义如下:

int fputs(const char* buff, FILE* fp)

1)参数:
   buff:  char*类型,指向被写入的字符串;
   fp:  FILE*类型,代表目标写入的文件指针;
   
2)返回值(int类型):
   非负数:代表写入成功;
   EOF:  代表写入出现错误;

      案例:

char data[10] = {"hello\0"};
​
// 写入一行字符串
int result = fputs(data, fp);

     4、读取一行字符

      定义如下:

  char* fgets(char* buff, int size, FILE* fp)

1)参数:
   buff: 代表存放读取结果的字符数组;   
   size: 代表本次读取的最大字符个数;
   fp  :  FILE*类型,代表想要读取的文件指针;
   
2)返回值:
   如果读取成功,返回指向字符串的指针,和传入的buff指针变量值相同;
   如果读取失败,返回NULL;

         如果读到最大个数字符,并且还没有读到换行符,就直接返回本次读取的数据。

         如果读到换行符,直接返回本次读取的数据。

 

     案例:

char data[10];
​
// 读取一行字符串
// 本次最多读取10个字符
char* p = fgets(data, 10, fp);
​
printf("读取结果:%s", data);

     5、格式化读取

     定义如下:

int fscanf(FILE* fp,  const char* format,  ...)

1)参数:
   fp :  FILE*类型,代表读取的文件指针;
   format :  char类型,约定的格式字符串;例如"%d %c";
   ... : 可根据实际传入变量的指针列表,例如"&a, &b, &c";
​
2)返回值(int类型):
    代表本次读取成功填充的参数个数。例如本次传入3个参数,如果全部读取成功,会返回3个。

     案例:

         假设此时文件的内容是"a=22,b=55"。

 int a;
 int b;

 // 按照约定的格式读取
 int result = fscanf(fp, "a=%d,b=%d", &a, &b);
 
 printf("a=%d, b=%d\n", a, b);

     6、格式化输出

      定义如下:

  格式化输出变量值
  int fprintf(FILE* fp,  char* format,  ...)

1)参数:
   fp  :  FILE*类型,代表目标写入的文件指针;
   format :  char*类型,指向存放格式化字符串的指针;
   ... :  代表被输出的变量序列,例如"a, b, c";
   
2)返回值(int类型):
   代表本次输出成功的字符个数。
   
注意:fprintf()不使用缓冲;   

     案例如下:

int a = 100;
float b = 3.14
char name[6] = {"hello\0"};
​
int result = fprintf(fp, "a=%d,b=%f,name=%s\n", a, b, name);
​
// 如果写入成功,文件中增加内容为:"a=100,b=3.14,name=hello"。

  (五)读写二进制文件

       1、读取二进制数据块

           作用是一次性读取多个字节;

 

    定义如下:

  int fread(void* buff,  int unit, int size, FILE* fp) 

  从文件中读取数据块到缓冲区。
​
1)参数:
   buff :  代表读取后的数据存放位置的指针;例如字符数组名、结构体变量指针。
   unit :  代表本次的读取单元有几个字节;一般用sizeof()来获得变量的占用字节数;
   size :  代表本次连续读取几个数据单元;
   fp  :  FILE*类型,代表读取的文件指针;
   
2)返回值(int类型):
   代表本次成功读取的数据单元个数;
  

    案例:

  char buff[100];
  
  // 本次读取,每个单元有1个字节,目标读取10个单元,文件指针是fp
  int size = fread(buff, 1, 10, fp);
  
  printf("读取单元个数:%d \n", size);
  
  printf("读取结果:%s \n", buff);
  
  // 假设有结构体变量struct stu stu1,读取一个结构体数据:
  int size = fread(&stu1, sizeof(struct stu), 1, fp);

      2、写入二进制数据块

         作用是能一次性写入多个字节;

 

     定义如下:

  int fwrite(void* buff,  int unit,  int size, FILE* fp) 
    写入数据块到文件中。
​
 1)参数
   buff :  代表被输出的数据存放的指针;例如字符数组名、结构体变量指针。
   unit :  代表本次的写入数据单元有几个字节;一般用sizeof()来获得变量的占用字节数;
   size :  代表本次连续写入几个数据单元;
   fp  :  FILE*类型,代表用来写入的文件指针;

   
 2)返回值(int类型):
   代表本次成功写入的数据单元个数;

     案例:

 char buff[100] = {"hello"};
  
  // 本次写入,每个单元有1个字节
  // 写入单元数需要获取字符长度
  // 写入的文件指针是fp
  int size = fwrite(buff, 1, strlen(buff), fp);
  
  printf("读取写入个数:%d \n", size);
  

 


   (六)操作文件指针的函数

        1、返回当前读取的文件指针位置。

         定义如下:

  int ftell(FILE* fp)
  
  1)参数:
   fp  :  FILE*类型,代表目标文件指针;
​
  2)返回值:
    返回代表从第一个字节开始计数,向后移动就加一,直到当前字节的位置整数;
    如果是0,代表指向文件的第一个字节;

       2、把读取指针重新定位到第一个字节。

         如果文件读取过很多次后,还想重新读取,就能调用"rewind(FILE* fp)"来恢复到初始位置;

         定义如下:

  void rewind(FILE* fp)

1)参数:
   fp  :  FILE*类型,代表目标文件指针;
  
2)返回值:
   没有返回值。

      3、定位到文件的任意一个字节位置。

       定义如下:

  int fseek(FILE* fp, long int offset,  int start) 
​
 1)参数:
   fp:  FILE*类型,代表操作的文件指针;
   offset :  long int类型,表示从某个相对位置开始的偏移量;如果是正值向后偏移,如果是负值,向前偏移;
   start: 这是偏移量的相对位置,设置为三个常量之一:
           SEEK_SET 从文件开头开始;
           SEEK_CUR  从当前位置开始计数;
           SEEK_END  从文件的末尾开始计数;
​
2)返回值(int类型):
   如果成功,返回0;
   如果失败,返回一个非零整数;

案例:

// 1、重定向在距离开头5个字节的位置(文件索引从0开始)
fseek(fp, 5 - 1, SEEK_SET);
​
// 2、重定向在开头第一个字节的位置
fseek(fp, 0, SEEK_SET);
​
// 3、重定向在末尾开始的第一个字节的位置
fseek(fp, 0, SEEK_END);
​
// 4、重定向当前的上一个位置
fseek(fp, -1, SEEK_CUR);

      4、判断文件末尾

  int feof(FILE* fp) 
  
1)参数:
   fp :  FILE*类型,代表被判断的文件指针;
​
2)返回值(int类型):
  如果到文件末尾,返回非零值;
  如果没有到末尾,返回0;

      5、关闭文件

int fclose(FILE* fp)
​
1)参数:
   fp:  FILE*类型,代表关闭的文件指针;
   
2)返回值(int类型):
  如果关闭成功,返回0;
  如果关闭失败,返回常量EOF值;
   

 


    (七)其他函数

        1、重新打开文件

          主要用来重定向流;

 

     定义如下:

int freopen(const char* filepath, const char* mode, FILE* fp)  
​
1)参数:
   filepath: 代表需要被打开的那个文件路径;
   mode: char*类型,指定文件的打开模式;具体定义和fopen()一样;
   fp: FILE*类型,是传入一个已经定义的文件指针;
​
2)返回值:
   如果打开成功,返回指向文件流的指针。
   如果打开失败,返回NULL。

   案例:

// 把stdout重定向到文件里
FILE* fp = freopen("D:/m.txt", "w+", stdout);
​
// 输出字符
printf("hello\n");
​
// 此时printf()函数的内容被输出到D:/m.txt文件中。

     2、刷新缓冲区

      定义如下:

int fflush(FILE* fp) 
​
1)参数:
   fp:  FILE*类型,代表被刷新的文件指针;
​
2)返回值:
   如果成功,返回0;
   如果失败,返回EOF常量值。

     3、设置缓冲模式

  int setvbuf(FILE* fp, char* buff, int mode, int size) 
​
1)参数:
   fp:  FILE*类型,代表被设置的文件指针;
   buff:  被设置的缓冲区,一般是char字符数组;如果为NULLL,自动创建;
   mode: 指定缓冲模式,是下面的任意一个常量:
          _IOFBF: 全缓冲 
          _IOLBF: 行缓冲
          _ILNBF: 没有缓冲
   size: 设置缓冲区字节的大小,是一个整数;       
​

2)返回值:
   如果成功,返回0;
   如果失败,返回非零值;
​

      4、手动设置缓冲区

void setbuf(FILE* fp, char* buff)
​
1)参数
  fp : 目标文件指针;
  buff: 是用来缓冲数据的字符数组指针;
  
2)返回值
 没有返回值。  
​

    案例:

char buff[100];
​
// 把buff设置为缓冲区
setbuf(fp, buff);
​

     5、判断文件是否出现错误。

int ferror(FILE* fp) 
​
1)参数
   fp: 被判断的文件指针;
   
2)返回值
   如果有错误,返回一个非零的整数;
   如果没有错误,返回0。

     6、生成一个临时文件名字。

     定义:

 char* tmpnam(char* buff)
 
 1)参数:
   buff: 是存放生成的文件名存放的位置;一般是传入char类型的数组名;
   
2)返回值:
   如果生成成功,返回和buff一样的指针;
   如果失败,返回NULL。

    7、返回一个临时文件

 FILE* tmpfile()  
 
 1)参数:
    不需要参数。
    
 2)返回值:
   如果执行成功,返回指向临时文件的FILE*文件指针;
   如果执行失败,返回NULL。

     8、重命名

int rename(const char* old_name, const char* new_name)
​
1)参数:
  old_name:  指向旧文件名字的字符串指针;
  new_name:  指向文件新名字的字符串指针;
  
2)返回值(int类型):
  如果成功,返回0;
  如果失败,返回-1。

    案例:

  int result = rename("D:/oo.txt", "D:/mu.txt");
  
  printf("重命名是否成功:%d \n", result);

 

四、使用经验

(一)fread和fwrite可以指定每个数据单位占用几个字节(方便读写结构体变量)。

 

(二)文件读写的缓冲区使用char类型的数组来充当。

 

(三)stdio.h库有默认的缓冲流变量:

     stdin 代表标准输入流(控制台输入)。

     stdout 代表标准输出流。

     stderr 代表标准错误流。

 

(四)void*类型的指针可以强制转化。 按照指定的格式来读写内存。

例如:

        把void*转成int*类型,那么把连续的4个字节看做是一个int整型变量值。

        如果把void*转成char*类型,那么每个字节都看做是一个字符。

 

(五)实际可以用二进制模式来读写文本文件。

例如: FILE*fp = fopen("D:/m.txt", "w+b");

 

(六)常量EOF的整型值是-1。

  #define EOF -1

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值