C语言---文件读写

文章目录

  • [1. 核心概念:文件指针 (FILE *)](#1. 核心概念:文件指针 (FILE *))
  • [2. 文件的打开与关闭](#2. 文件的打开与关闭)
    • [2.1 打开文件:fopen()](#2.1 打开文件:fopen())
    • [2.2 关闭文件:fclose()](#2.2 关闭文件:fclose())
  • [3. 文件的读写操作](#3. 文件的读写操作)
    • [3.1 字符读写 (Character I/O)](#3.1 字符读写 (Character I/O))
    • [3.2 字符串/行读写 (Line I/O)](#3.2 字符串/行读写 (Line I/O))
    • [3.3 格式化读写 (Formatted I/O)](#3.3 格式化读写 (Formatted I/O))
    • [3.4 块读写 (Binary/Block I/O)](#3.4 块读写 (Binary/Block I/O))
  • [4. 文件定位 (Random Access)](#4. 文件定位 (Random Access))
  • [5. 错误处理](#5. 错误处理)
  • [7. 常见陷阱与最佳实践](#7. 常见陷阱与最佳实践)

C语言的文件读写(File I/O)是C标准库(stdio.h)提供的一套强大功能,用于在程序和外部文件(如txt、dat、csv等)之间传输数据。

以下是C语言文件操作的核心知识体系,包含基本概念、常用函数、操作模式和完整示例。

1. 核心概念:文件指针 (FILE *)

在C语言中,文件被看作是一个字节流。系统通过一个结构体 FILE 来管理文件的状态(如当前读写位置、错误标志、文件缓冲区等)。

我们不直接操作 FILE 结构体,而是通过 文件指针 (FILE *) 来引用它。

标准输入/输出也是文件:stdin(键盘)、stdout(屏幕)、stderr(错误输出)。

2. 文件的打开与关闭

2.1 打开文件:fopen()

在读写文件前,必须先打开文件。

bash 复制代码
FILE *fopen(const char *filename, const char *mode);

filename: 文件路径(如 "data.txt" 或 "C:\test\data.bin")。

mode: 打开模式(字符串)。

模式 含义 文件不存在时
"r" 只读(文本) 报错 (NULL)
"w" 只写(文本) 创建新文件
"a" 追加(文本) 创建新文件
"r+" 读写(文本) 报错
"w+" 读写(文本) 创建新文件(覆盖原内容)
"a+" 读写(追加) 创建新文件
二进制模式 (在上述后加 b)
"rb" 只读(二进制) 报错
"wb" 只写(二进制) 创建新文件

注意:文本模式下,Windows会将 \n 转换为 \r\n,而Linux/Mac不会;二进制模式 (b) 则原样读写,适合图片、音频、结构体。

2.2 关闭文件:fclose()

操作完成后必须关闭文件,以释放资源并将缓冲区数据刷新到磁盘。

bash 复制代码
int fclose(FILE *stream);
// 成功返回0,失败返回EOF(-1)

3. 文件的读写操作

根据读取数据的单位不同,分为四类:

3.1 字符读写 (Character I/O)

适用于逐个字符处理。

int fgetc(FILE *fp): 读取一个字符,返回其ASCII码,失败或EOF返回 EOF。

int fputc(int c, FILE *fp): 写入一个字符。

bash 复制代码
// 示例:复制文件(字符版)
char ch;
while ((ch = fgetc(fin)) != EOF) {
    fputc(ch, fout);
}

3.2 字符串/行读写 (Line I/O)

适用于读取配置文件、日志等文本。

char *fgets(char *buf, int size, FILE *fp): 读取一行(最多 size-1 个字符),安全(防止溢出),会保留换行符 \n。

int fputs(const char *s, FILE *fp): 写入字符串(不自动加 \n)。

bash 复制代码
char buffer[100];
if (fgets(buffer, 100, fp) != NULL) {
    printf("Read line: %s", buffer);
}

3.3 格式化读写 (Formatted I/O)

用法与 printf / scanf 完全一致,只是针对文件。

int fprintf(FILE *fp, const char *format, ...): 格式化写入。

int fscanf(FILE *fp, const char *format, ...): 格式化读取。

bash 复制代码
int age = 25;
fprintf(fp, "Name: %s, Age: %d\n", "Alice", age);

3.4 块读写 (Binary/Block I/O)

适用于结构体、数组、图片等二进制数据,效率最高。

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp): 从文件读入数据块到内存。

size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp): 将内存数据块写入文件。

bash 复制代码
// 示例:写入结构体
struct Student { int id; char name[20]; };
struct Student s = {1, "Tom"};
fwrite(&s, sizeof(struct Student), 1, fp);

// 示例:读取结构体
fread(&s, sizeof(struct Student), 1, fp);

4. 文件定位 (Random Access)

不一定要顺序读写,可以跳转到文件任意位置。

1、int fseek(FILE *fp, long offset, int whence): 移动文件指针。

Parameter analysis:

whence: SEEK_SET(文件头), SEEK_CUR(当前位置), SEEK_END(文件尾)。

2、long ftell(FILE *fp): 获取当前文件指针位置。

3、void rewind(FILE *fp): 将指针重置到文件开头。

5. 错误处理

文件操作非常容易出错(如磁盘满、无权限、文件被占用),必须检查返回值。

1、fopen失败: 返回 NULL。

2、ferror(FILE *fp): 检查文件流是否发生错误。

3、feof(FILE *fp): 检查是否到达文件末尾(End Of File)。

4、perror(): 打印系统错误信息。

bash 复制代码
FILE *fp = fopen("nonexist.txt", "r");
if (fp == NULL) {
    perror("Error opening file"); // 输出类似: Error opening file: No such file or directory
    return 1;
}

7. 常见陷阱与最佳实践

1、忘记关闭文件:会导致数据丢失(数据还在缓冲区没写入磁盘)和资源泄漏。

2、不检查返回值:fopen 可能失败,fread 可能读不满。

3、模式混淆:用 "r" 读二进制文件(如jpg)会出错,因为系统可能对字节 0x1A 做特殊处理(在4、4、DOS/Windows下视为EOF)。读写非纯文本文件务必用 b 模式。

5、路径问题:Windows下路径分隔符是 \(因为 \ 是转义符),或者使用正斜杠 /(C标准库支持)。

6、缓冲区:fopen 默认是全缓冲(除 stderr 外)。数据不会立即写入磁盘,除非缓冲区满、遇到 \n(行缓冲)或调用 fflush() / fclose()。

相关推荐
她说..1 天前
策略模式+工厂模式实现单接口适配多审核节点
java·spring boot·后端·spring·简单工厂模式·策略模式
f狐0狸x1 天前
【C++修炼之路】C++ list容器基本用法详解
开发语言·c++·list
坚持就完事了1 天前
Java的OOP
java·开发语言
jllllyuz1 天前
基于MATLAB的锂电池物理对象建模实现
开发语言·matlab
MyBFuture1 天前
C#数组详解:一维二维与交错数组
开发语言·windows·c#·visual studio·vision pro
像少年啦飞驰点、1 天前
零基础入门 Spring Boot:从“Hello World”到可部署微服务的完整学习路径
java·spring boot·微服务·编程入门·后端开发
程序 代码狂人1 天前
CentOS7初始化配置操作
linux·运维·开发语言·php
从此不归路1 天前
Qt5 进阶【13】桌面 Qt 项目架构设计:从 MVC/MVVM 到模块划分
开发语言·c++·qt·架构·mvc
zhangx1234_1 天前
C语言 数据在内存中的存储
c语言·开发语言
星空露珠1 天前
速算24点检测生成核心lua
开发语言·数据库·算法·游戏·lua