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()。

相关推荐
陌路202 小时前
C++30 STL容器 -deque双端队列
开发语言·c++
xb11322 小时前
C#委托详解
开发语言·c#
brent4232 小时前
DAY50复习日
开发语言·python
木头程序员2 小时前
前端(包含HTML/JavaScript/DOM/BOM/jQuery)基础-暴力复习篇
开发语言·前端·javascript·ecmascript·es6·jquery·html5
Data_agent3 小时前
Cocbuy 模式淘宝 / 1688 代购系统(欧美市场)搭建指南
开发语言·python
wszy18093 小时前
外部链接跳转:从 App 打开浏览器的正确姿势
java·javascript·react native·react.js·harmonyos
lsx2024063 小时前
《Foundation 下拉菜单》
开发语言
期待のcode3 小时前
认识Java虚拟机
java·开发语言·jvm
raining_peidx3 小时前
xxljob源码
java·开发语言