C语言备忘录 - 19. 文件读写

一、fgetc() 与 fputc()

#include <stdio.h>

int fgetc(FILE *stream);
int fputc(int c, FILE *stream);
  • fgetc() 用于从文件流中读取下一个字符并推进文件的位置指示器,该函数将读取到的 unsigned char 类型转换为 int 类型并返回;如果文件结束或者遇到错误则返回 EOF。
  • fputc() 用于将一个字符写入到指定的文件中并推进文件的位置指示器,如果写入成功,它会返回写入的字符,如果发生错误,则会返回 EOF。
#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE *fpr;
  FILE *fpw;
  int ch;

  /* 以只读模式打开本地 hello.txt 文件 */
  if ((fpr = fopen("./hello.txt", "r")) == NULL) {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }
  /* 以写入模式打开 hello1.txt 文件,不存在就创建 */
  if ((fpw = fopen("./hello1.txt", "w")) == NULL) {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }

  /* 循环从文件中读取一个字符 */
  while ((ch = fgetc(fpr)) != EOF) {
    /* 打印字符到标准输出 */
    putchar(ch);
    /* 打印字符到 fpw 文件流 */
    fputc(ch, fpw);
  }

  /* 关闭文件 */
  fclose(fpr);
  fclose(fpw);

  return 0;
}

二、fgets() 与 fputs()

#include <stdio.h>

/*
 buff:用于存放读取到字符串的缓冲区
 size:指定读取的字符数(包括最后自动添加的 '\0')
 stream:待操作的文件流
 */
char *fgets(char *buff, int size, FILE *stream);
int fputs(const char *s, FILE *stream);
  • fgets() 用于读取字符串到 buff 缓冲区,最多可以读取 size - 1 个字符,因为结尾处会自动添加一个字符串结束符 '\0'。当读取到换行符('\n')或文件结束符(EOF)时,表示结束读取('\n' 会被作为一个合法的字符读取)。如果函数调用成功,返回 buff 参数指向的地址。
  • fputs() 用于将一个字符串写入到指定的文件中,表示字符串结尾的 '\0' 不会被一并写入。如果写入成功,它会返回一个非0值,如果发生错误,则会返回 EOF。
#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE *fpr;
  FILE *fpw;
  char str[50];

  /* 以只读模式打开本地 hello.txt 文件 */
  if ((fpr = fopen("./hello.txt", "r")) == NULL) {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }
  /* 以写入模式打开 hello1.txt 文件,不存在就创建 */
  if ((fpw = fopen("./hello1.txt", "w")) == NULL) {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }

  while (1) {
    /* 读取字符串到缓冲区 */
    fgets(str, 50, fpr);
    /* 文件末尾指示器被设置时结束循环 */
    if (feof(fpr)) {
      break;
    }
    /* 打印字符串到标准输出 */
    printf("%s", str);
    /* 打印字符串到 fpw 文件流 */
    fputs(str, fpw);
  }

  /* 关闭文件 */
  fclose(fpr);
  fclose(fpw);

  return 0;
}

三、fscanf() 与 fprintf()

#include <stdio.h>

/*
 format 格式化字符串,由格式化占位符和普通字符组成
 ... 附加参数
 */
int fscanf(FILE *stream, const char *format, ...);
int fprintf(FILE *stream, const char *format, ...);
  • fscanf() 用于从指定文件中读取格式化字符串。如果函数调用成功,返回值是成功获取并填充到附加参数中的个数。如果函数调用失败,返回值小于附加参数的个数(甚至是 0)。如果读取到标准输入流的结尾处,则返回 EOF。
  • fprintf() 用于打印格式化字符串到指定的文件。如果函数调用成功,返回值是实际打印的字符数(不包含表示字符串结束的 '\0');如果函数调用失败,返回值是一个负数。
#include <stdio.h>
#include <stdlib.h>

int main()
{
  FILE *fpr;
  FILE *fpw;
  int year, month, day;

  /* 以只读模式打开本地 hello.txt 文件 */
  if ((fpr = fopen("./hello.txt", "r")) == NULL)
  {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }
  /* 以写入模式打开 hello1.txt 文件,不存在就创建 */
  if ((fpw = fopen("./hello1.txt", "w")) == NULL)
  {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }

  int ch;
  while ((ch = fscanf(fpr, "%d-%d-%d", &year, &month, &day)) != EOF)
  {
    /* 打印数据到标准输出 */
    printf("%d-%d-%d\n", year, month, day);
    /* 打印数据到 fpw 文件流*/
    fprintf(fpw, "%d-%d-%d\n", year, month, day);
  }

  /* 关闭文件 */
  fclose(fpr);
  fclose(fpw);

  return 0;
}

四、fread() 与 fwrite()

#include <stdio.h>

/*
 ptr:指向存放数据的内存块指针,该内存块的尺寸最小应该是 size * nmemb 个字节
 size:指定要读取/写入的每个元素的尺寸,最终尺寸等于 size * nmemb
 nmemb:指定要读取/写入的元素个数,最终尺寸等于 size * nmemb
 stream:待操作的文件流
 */
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);
  • fread() 用于从指定的文件中读取指定尺寸的数据。返回实际读取到的元素个数(nmemb);如果返回值比 nmemb 参数的值小,表示可能读取到文件末尾或者有错误发生(可以使用 feof 函数或 ferror 函数进一步判断)。
  • fwrite() 用于将指定尺寸的数据写入到指定的文件中。返回实际写入到文件中的元素个数(nmemb);如果返回值与 nmemb 参数的值不同,则有错误发生。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Book
{
  char name[50];
  char author[50];
};

int main()
{
  FILE *fpr;
  FILE *fpw;
  struct Book *book;

  // 为结构体分配堆内存空间
  book = (struct Book *)malloc(sizeof(struct Book));
  if (book == NULL) {
    printf("内存分配失败!\n");
    exit(EXIT_FAILURE);
  }
  strcpy(book->name, "C语言备忘录");
  strcpy(book->author, "liwy");

  /* 以写入模式打开 hello1.txt 文件,不存在就创建 */
  if ((fpw = fopen("./hello.txt", "w")) == NULL) {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }
  /* 将数据写入文件 */
  fwrite(book, sizeof(struct Book), 1, fpw);
  /* 关闭文件 */
  fclose(fpw);

  /* 以只读模式打开本地 hello.txt 文件 */
  if ((fpr = fopen("./hello.txt", "r")) == NULL) {
    printf("文件打开失败!");
    exit(EXIT_FAILURE);
  }
  /* 读取指定尺寸的数据 */
  fread(book, sizeof(struct Book), 1, fpr);
  printf("书名:%s\n", book->name);
  printf("作者:%s\n", book->author);
  /* 关闭文件 */
  fclose(fpr);

  return 0;
} 

五、IO缓冲区

对于数据流,有三种缓存模式:不缓存,按块缓存和按行缓存。如果输出流设置为不缓存,数据会直接写入目标文件或打印到屏幕上;如果设置为按块缓存,那么数据会先写入到缓存块中;如果设置为按行缓存,那么在接收到换行符('\n')之前,数据都是先缓存在缓冲区的。

1. fflush()

用于将缓冲区内的数据强制写入指定的文件中。

#include <stdio.h>

int fflush(FILE *stream);

如果函数调用成功,返回值是 0;如果函数调用失败,返回 EOF 并设置 errno 为指定的错误。

2. setvbuf()

用于指定一个数据流的缓存模式。

#include <stdio.h>

int setvbuf(FILE *stream, char *buf, int mode, size_t size);
  • stream :该参数是一个 FILE 对象的指针,指定一个打开的数据流
  • buf :指定一个用户分配的缓冲区,如果该参数为 NULL,那么函数会自动分配一个指定尺寸的缓冲区
  • mode :指定数据流的缓存模式:_IOFBF(按块缓存)、_IOLBF(按行缓存)、_IONBF(不缓存)
  • size :指定缓冲区的尺寸(字节)

如果函数调用成功,返回值是 0;如果函数调用失败,返回值的是一个非 0 值。

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

int main(void)
{
  char buff[1024];
  memset(buff, '\0', sizeof(buff));

  /* 按块缓冲,当缓冲区写满时才写入文件 */
  setvbuf(stdout, buff, _IOFBF, 1024);

  fprintf(stdout, "Hello C!\n");

  /* 强制将缓冲区内容写入文件 */
  fflush(stdout);

  fprintf(stdout, "Hello liwy!\n");

  // 阻塞, Hello liwy! 将不会输出
  getchar();

  return 0;
}
原文链接:,转发请注明来源!