C语言 标准I/O函数全面指南 - 指南

C标准I/O函数全面指南

本指南详细介绍了C语言中用于文件操作的标准输入/输出函数,包括单字符I/O、字符串I/O、格式化I/O、块I/O以及文件光标操作。每个部分包含函数定义、使用说明和实用示例,适合学习、复习以及博客发布。内容采用清晰的Markdown格式,代码规范,包含详细注释和最佳实践(如错误处理),以提升可读性和实用性。


1. 单字符读写:fputcfgetc

函数定义

  • fgetc

    #
    include <stdio.h>
      int fgetc(FILE *stream)
      ;
    • 功能:从指定文件中读取一个字符,并以无符号整数形式返回。
    • 参数stream - 文件指针。
    • 返回值
      • 成功:返回读取的字符(无符号整数形式)。
      • 失败:返回EOF并设置错误码。
  • fputc

    #
    include <stdio.h>
      int fputc(
      int c, FILE *stream)
      ;
    • 功能:将指定字符c写入到文件指针stream指向的文件中。
    • 参数
      • c:要写入的字符(以无符号整数形式传递)。
      • stream:文件指针。
    • 返回值
      • 成功:返回写入的字符(无符号整数形式)。
      • 失败:返回EOF并设置错误码。

示例代码

以下示例展示如何使用fputc写入字符到文件,并用fgetc读取文件内容。

#
include <stdio.h>
  int main(
  ) {
  // 定义文件指针
  FILE *fp = NULL
  ;
  // 以只写模式打开文件
  if ((fp = fopen("file.txt"
  , "w"
  )
  ) == NULL
  ) {
  perror("fopen error"
  )
  ;
  return -1
  ;
  }
  // 写入字符串 "Hello",每次写入一个字符
  fputc('H'
  , fp)
  ;
  fputc('e'
  , fp)
  ;
  fputc('l'
  , fp)
  ;
  fputc('l'
  , fp)
  ;
  fputc('o'
  , fp)
  ;
  fclose(fp)
  ;
  // 关闭文件
  // 以只读模式重新打开文件
  if ((fp = fopen("file.txt"
  , "r"
  )
  ) == NULL
  ) {
  perror("fopen error"
  )
  ;
  return -1
  ;
  }
  // 逐字符读取并打印
  char ch;
  while ((ch = fgetc(fp)
  ) != EOF
  ) {
  printf("%c "
  , ch)
  ;
  }
  fclose(fp)
  ;
  // 关闭文件
  return 0
  ;
  }

说明

  • 写入fputc每次写入一个字符,文件光标自动向后移动。
  • 读取fgetc每次读取一个字符,遇到文件末尾返回EOF
  • 注意:写入后光标位于文件末尾,直接读取会失败,因此需重新打开文件或使用rewind重置光标。

2. 字符串读写:fgetsfputs

函数定义

  • fputs

    #
    include <stdio.h>
      int fputs(
      const
      char *s, FILE *stream)
      ;
    • 功能:将字符串s写入到文件指针stream指向的文件中(不包含字符串结束符\0)。
    • 参数
      • s:要写入的字符串。
      • stream:文件指针。
    • 返回值
      • 成功:返回写入的字符数(非负数)。
      • 失败:返回EOF
  • fgets

    #
    include <stdio.h>
      char *fgets(
      char *s,
      int size, FILE *stream)
      ;
    • 功能:从文件指针stream指向的文件中读取最多size-1个字符到数组s,遇到换行符或文件末尾停止,并在末尾自动添加\0
    • 参数
      • s:存储读取数据的字符数组。
      • size:最多读取的字符数(包含末尾\0)。
      • stream:文件指针。
    • 返回值
      • 成功:返回s(字符数组起始地址)。
      • 失败或文件末尾:返回NULL

示例代码

以下示例展示如何从终端输入字符串并写入文件,再从文件中读取并显示。

#
include <stdio.h>
  #
  include <string.h>
    int main(
    ) {
    // 定义文件指针
    FILE *fp = NULL
    ;
    // 以只写模式打开文件
    if ((fp = fopen("file.txt"
    , "w"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 从终端输入字符串并写入文件
    char wbuf[128]
    ;
    while (1
    ) {
    printf("请输入字符串(输入quit退出):"
    )
    ;
    fgets(wbuf,
    sizeof(wbuf)
    , stdin
    )
    ;
    // 从标准输入读取
    wbuf[strcspn(wbuf, "\n"
    )] = '\0'
    ;
    // 移除换行符
    if (strcmp(wbuf, "quit"
    ) == 0
    ) {
    break
    ;
    }
    fputs(wbuf, fp)
    ;
    // 写入字符串
    fputc('\n'
    , fp)
    ;
    // 添加换行符
    }
    fclose(fp)
    ;
    // 以只读模式打开文件
    if ((fp = fopen("file.txt"
    , "r"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 逐行读取并打印
    char rbuf[128]
    ;
    while (fgets(rbuf,
    sizeof(rbuf)
    , fp) != NULL
    ) {
    printf("读取到:%s"
    , rbuf)
    ;
    }
    fclose(fp)
    ;
    return 0
    ;
    }

说明

  • 写入fputs写入字符串,不包括\0,需手动添加换行符以分隔行。
  • 读取fgets读取一行(包含换行符),自动添加\0,适合逐行处理文本文件。
  • 注意fgets会保留输入的换行符,需用strcspn或类似方法移除。

3. 格式化读写:fprintffscanf

函数定义

  • fprintf

    #
    include <stdio.h>
      int fprintf(FILE *stream,
      const
      char *format, ...
      )
      ;
    • 功能:按指定格式将数据写入文件。
    • 参数
      • stream:文件指针(可为stdoutstderr)。
      • format:格式化字符串,包含格式控制符(如%d%s%f%lf)。
      • ...:可变参数,数量由格式控制符决定。
    • 返回值
      • 成功:返回写入的字符数。
      • 失败:返回负数。
  • fscanf

    #
    include <stdio.h>
      int fscanf(FILE *stream,
      const
      char *format, ...
      )
      ;
    • 功能:按指定格式从文件中读取数据到变量中。
    • 参数
      • stream:文件指针(可为stdin)。
      • format:格式化字符串,包含格式控制符。
      • ...:变量地址列表,数量由格式控制符决定。
    • 返回值
      • 成功:返回成功读取的项数。
      • 失败或文件末尾:返回EOF并设置错误码。

示例代码

以下示例展示格式化读写到标准输出/输入和外部文件。

#
include <stdio.h>
  int main(
  ) {
  // 向标准输出写入格式化数据
  fprintf(stdout
  , "整数: %d, 小数: %.2f, 字符串: %s\n"
  , 520
  , 3.14
  , "I Love C"
  )
  ;
  // 从标准输入读取整数
  int num;
  printf("请输入一个整数:"
  )
  ;
  if (fscanf(stdin
  , "%d"
  , &num) == 1
  ) {
  printf("读取到:%d\n"
  , num)
  ;
  }
  else {
  printf("读取失败\n"
  )
  ;
  }
  // 写入格式化数据到文件
  FILE *fp = NULL
  ;
  if ((fp = fopen("usr.txt"
  , "w"
  )
  ) == NULL
  ) {
  perror("fopen error"
  )
  ;
  return -1
  ;
  }
  fprintf(fp, "%s %d"
  , "admin"
  , 123456
  )
  ;
  // 写入用户名和密码
  fclose(fp)
  ;
  // 从文件中读取格式化数据
  if ((fp = fopen("usr.txt"
  , "r"
  )
  ) == NULL
  ) {
  perror("fopen error"
  )
  ;
  return -1
  ;
  }
  char usrName[20]
  ;
  int pwd;
  if (fscanf(fp, "%s %d"
  , usrName, &pwd) == 2
  ) {
  printf("用户名: %s, 密码: %d\n"
  , usrName, pwd)
  ;
  }
  else {
  printf("读取失败\n"
  )
  ;
  }
  fclose(fp)
  ;
  return 0
  ;
  }

说明

  • 格式化fprintffscanf支持多种数据类型(如整数、浮点数、字符串),灵活性高。
  • 标准I/O:使用stdoutstdin可直接操作终端输入输出。
  • 注意fscanf读取时需确保变量地址正确,格式匹配,否则可能导致错误。

4. 格式串转字符串:sprintfsnprintf

函数定义

  • sprintf

    #
    include <stdio.h>
      int sprintf(
      char *str,
      const
      char *format, ...
      )
      ;
    • 功能:将格式化数据转换为字符串,存储到字符数组str中。
    • 参数
      • str:目标字符数组。
      • format:格式化字符串。
      • ...:可变参数。
    • 返回值
      • 成功:返回转换的字符数(不含\0)。
      • 失败:返回EOF
  • snprintf

    #
    include <stdio.h>
      int snprintf(
      char *str, size_t size,
      const
      char *format, ...
      )
      ;
    • 功能:将格式化数据转换为字符串,最多存储size-1个字符到str,并添加\0
    • 参数
      • str:目标字符数组。
      • size:最大存储字符数(含\0)。
      • format:格式化字符串。
      • ...:可变参数。
    • 返回值
      • 成功:返回应写入的字符数(不含\0)。
      • 如果超出size:返回应写入的字符数(但只写入size-1个字符)。
      • 失败:返回EOF

示例代码

以下示例展示如何将多种数据类型组合成字符串。

#
include <stdio.h>
  int main(
  ) {
  char buf[20]
  ;
  // 使用 sprintf(不安全,可能溢出)
  sprintf(buf, "%d %s %.1f"
  , 1001
  , "zhangsan"
  , 99.5
  )
  ;
  printf("sprintf结果: %s\n"
  , buf)
  ;
  // 使用 snprintf(安全,限制长度)
  snprintf(buf,
  sizeof(buf)
  , "%d %s %.1f"
  , 1001
  , "zhangsan"
  , 99.5
  )
  ;
  printf("snprintf结果: %s\n"
  , buf)
  ;
  return 0
  ;
  }

说明

  • 安全性sprintf可能导致缓冲区溢出,推荐使用snprintf以限制写入长度。
  • 用途:常用于将多种数据类型组合成字符串,便于后续处理或输出。
  • 注意:确保buf大小足够容纳格式化结果,snprintf更适合现代编程。

5. 模块化读写:freadfwrite

函数定义

  • fread

    #
    include <stdio.h>
      size_t fread(
      void *ptr, size_t size, size_t nmemb, FILE *stream)
      ;
    • 功能:从文件读取nmemb项数据,每项大小为size字节,存储到ptr指向的内存。
    • 参数
      • ptr:存储数据的内存地址(支持任意类型)。
      • size:每项数据的大小(字节)。
      • nmemb:读取的项数。
      • stream:文件指针。
    • 返回值
      • 成功:返回实际读取的项数。
      • 失败或文件末尾:返回小于nmemb的值或0。
  • fwrite

    #
    include <stdio.h>
      size_t fwrite(
      const
      void *ptr, size_t size, size_t nmemb, FILE *stream)
      ;
    • 功能:将ptr指向的nmemb项数据(每项size字节)写入文件。
    • 参数
      • ptr:要写入的数据地址。
      • size:每项数据的大小(字节)。
      • nmemb:写入的项数。
      • stream:文件指针。
    • 返回值
      • 成功:返回实际写入的项数。
      • 失败:返回小于nmemb的值或0。

示例代码

字符串读写
#
include <stdio.h>
  #
  include <string.h>
    int main(
    ) {
    FILE *fp = NULL
    ;
    // 以只写模式打开文件
    if ((fp = fopen("test.txt"
    , "w"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 循环输入字符串并写入
    char wbuf[128]
    ;
    while (1
    ) {
    printf("请输入字符串(输入quit退出):"
    )
    ;
    fgets(wbuf,
    sizeof(wbuf)
    , stdin
    )
    ;
    wbuf[strcspn(wbuf, "\n"
    )] = '\0'
    ;
    if (strcmp(wbuf, "quit"
    ) == 0
    ) {
    break
    ;
    }
    fwrite(wbuf, strlen(wbuf)
    , 1
    , fp)
    ;
    // 写入字符串
    fwrite("\n"
    , 1
    , 1
    , fp)
    ;
    // 添加换行
    fflush(fp)
    ;
    // 刷新缓冲区
    }
    fclose(fp)
    ;
    // 以只读模式打开文件
    if ((fp = fopen("test.txt"
    , "r"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 读取并输出
    char rbuf[10]
    ;
    size_t res;
    while ((res = fread(rbuf, 1
    ,
    sizeof(rbuf) - 1
    , fp)
    ) >
    0
    ) {
    rbuf[res] = '\0'
    ;
    // 添加结束符
    fwrite(rbuf, 1
    , res, stdout
    )
    ;
    // 输出到终端
    }
    fclose(fp)
    ;
    return 0
    ;
    }
整数读写
#
include <stdio.h>
  int main(
  ) {
  FILE *fp = NULL
  ;
  // 以只写模式打开文件
  if ((fp = fopen("test.txt"
  , "w"
  )
  ) == NULL
  ) {
  perror("fopen error"
  )
  ;
  return -1
  ;
  }
  // 写入整数
  int num = 16
  ;
  fwrite(&num,
  sizeof(
  int
  )
  , 1
  , fp)
  ;
  fclose(fp)
  ;
  // 以只读模式打开文件
  if ((fp = fopen("test.txt"
  , "r"
  )
  ) == NULL
  ) {
  perror("fopen error"
  )
  ;
  return -1
  ;
  }
  // 读取整数
  int key;
  if (fread(&key,
  sizeof(
  int
  )
  , 1
  , fp) == 1
  ) {
  printf("读取到: %d\n"
  , key)
  ;
  }
  else {
  printf("读取失败\n"
  )
  ;
  }
  fclose(fp)
  ;
  return 0
  ;
  }
结构体读写
#
include <stdio.h>
  #
  include <string.h>
    typedef
    struct {
    char name[20]
    ;
    int age;
    double score;
    } Stu;
    int main(
    ) {
    FILE *fp = NULL
    ;
    // 以只写模式打开文件
    if ((fp = fopen("test.txt"
    , "w"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 定义并写入学生数据
    Stu students[] = {
    {
    "张三"
    , 18
    , 98.0
    }
    ,
    {
    "李四"
    , 20
    , 88.0
    }
    ,
    {
    "王五"
    , 16
    , 95.0
    }
    }
    ;
    fwrite(students,
    sizeof(Stu)
    , 3
    , fp)
    ;
    fclose(fp)
    ;
    // 以只读模式打开文件
    if ((fp = fopen("test.txt"
    , "r"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 读取并显示一个学生信息
    Stu temp;
    if (fread(&temp,
    sizeof(Stu)
    , 1
    , fp) == 1
    ) {
    printf("姓名: %s, 年龄: %d, 成绩: %.2f\n"
    , temp.name, temp.age, temp.score)
    ;
    }
    fclose(fp)
    ;
    return 0
    ;
    }

说明

  • 灵活性freadfwrite支持任意数据类型(如字符串、整数、结构体),适合二进制文件操作。
  • 注意:二进制读写需确保数据结构对齐一致,跨平台时需考虑字节序。

6. 文件光标操作:fseek, ftell, rewind

函数定义

  • fseek

    #
    include <stdio.h>
      int fseek(FILE *stream,
      long offset,
      int whence)
      ;
    • 功能:移动文件光标到指定位置。
    • 参数
      • stream:文件指针。
      • offset:偏移量(正:向后,负:向前,0:不动)。
      • whence:起始位置(SEEK_SET:文件开头,SEEK_CUR:当前位置,SEEK_END:文件末尾)。
    • 返回值
      • 成功:返回0。
      • 失败:返回-1并设置错误码。
  • ftell

    #
    include <stdio.h>
      long ftell(FILE *stream)
      ;
    • 功能:获取文件光标的当前偏移量(相对于文件开头)。
    • 参数stream - 文件指针。
    • 返回值
      • 成功:返回当前偏移量(字节)。
      • 失败:返回-1并设置错误码。
  • rewind

    #
    include <stdio.h>
      void rewind(FILE *stream)
      ;
    • 功能:将文件光标重置到文件开头(等效于fseek(stream, 0, SEEK_SET))。
    • 参数stream - 文件指针。
    • 返回值:无。

示例代码

以下示例展示如何操作文件光标并读取特定位置的数据。

#
include <stdio.h>
  #
  include <string.h>
    typedef
    struct {
    char name[20]
    ;
    int age;
    double score;
    } Stu;
    int main(
    ) {
    FILE *fp = NULL
    ;
    // 以读写模式打开文件
    if ((fp = fopen("test.txt"
    , "w+"
    )
    ) == NULL
    ) {
    perror("fopen error"
    )
    ;
    return -1
    ;
    }
    // 写入三个学生数据
    Stu students[] = {
    {
    "张三"
    , 18
    , 98.0
    }
    ,
    {
    "李四"
    , 20
    , 88.0
    }
    ,
    {
    "王五"
    , 16
    , 95.0
    }
    }
    ;
    fwrite(students,
    sizeof(Stu)
    , 3
    , fp)
    ;
    // 获取文件大小
    fseek(fp, 0
    , SEEK_END
    )
    ;
    printf("文件大小: %ld 字节\n"
    , ftell(fp)
    )
    ;
    // 移动光标到第二个学生
    fseek(fp,
    sizeof(Stu)
    , SEEK_SET
    )
    ;
    // 读取并显示第二个学生信息
    Stu temp;
    if (fread(&temp,
    sizeof(Stu)
    , 1
    , fp) == 1
    ) {
    printf("姓名: %s, 年龄: %d, 成绩: %.2f\n"
    , temp.name, temp.age, temp.score)
    ;
    }
    fclose(fp)
    ;
    return 0
    ;
    }

说明

  • 光标操作fseek灵活控制文件读取位置,ftell可用于计算文件大小。
  • 重置光标rewind适合在同一文件流中从头重新读取。
  • 注意:二进制文件操作时,偏移量需与数据结构大小对齐。

总结与注意事项

  • 文件操作流程:始终检查fopen返回值,确保文件打开成功;操作完成后使用fclose关闭文件。
  • 错误处理:使用perror或检查返回值捕获错误,确保程序健壮性。
  • 缓冲区管理:写入数据后可用fflush刷新缓冲区,确保数据及时写入。
  • 安全性:优先使用snprintf而非sprintf,避免缓冲区溢出。
  • 跨平台注意:二进制文件读写需考虑字节序和结构体对齐问题。
posted @ 2025-07-19 11:13  yfceshi  阅读(17)  评论(0)    收藏  举报