文章目录
文件的概念
什么是文件?
文件是储存在外部介质(磁盘之类的)上数据的集合
什么是流?
操作系统是以文件为单位对数据进行管理的,输入输出是数据传送的过程,像水一样流动。所以吧输入输出称为流(stream)。输入输出流。
c语言把文件看作是字符(字节)的序列,即由一个个字符/字节组成。一个输入输出流就是一个字节流或二进制流。
文件的分类
- ANSCll文件(文本文件):一个字节放一个ASCll码,需要转换才能读取
- 二进制文件(视频文件等):二进制文件是由计算机可以直接读取的二进制格式表示的数据文件
文件缓冲区
文件缓冲区能够提高文件读写的速度和效率。在计算机编程中,缓冲区是一个暂时存储数据的区域,这些数据最终会被写入磁盘或从磁盘读取出来。缓冲区的主要目的是减少磁盘访问次数,因为磁盘访问通常比内存(RAM)访问慢得多。
文件缓冲区的工作原理:
写入缓冲区:
- 当程序向文件写入数据时,这些数据首先被写入到内存中的缓冲区,而不是直接写入磁盘。
- 缓冲区会等待直到达到某个阈值(如缓冲区满或经过一定的时间间隔)才将数据刷新到磁盘上。
读取缓冲区:
- 当程序从文件读取数据时,数据被一次性读入到内存中的缓冲区。
- 程序可以从缓冲区读取数据,而无需直接访问磁盘。
文件指针
c语言内置的文件指针类型:
FILE*
在标准输入输出库中,系统定义了三个FILE型的指针变量:
1. stdin (stdin): 标准输入流
- 通常对应于用户的键盘输入。
- 也可以被重定向到一个文件或其他输入源。
- 可以通过 fgetc(stdin) 或 fgets(buffer, size, stdin) 等函数读取数据。
2. stdout (stdout): 标准输出流
- 通常输出到显示器屏幕。
- 也可以被重定向到一个文件或其他输出目的地。
- 可以通过 fputc(c, stdout) 或 printf 函数写入数据。
3. stderr (stderr): 标准错误输出流
- 用于输出错误信息或诊断信息。
- 通常也是输出到显示器屏幕,但它独立于标准输出流。
- 这意味着即使标准输出被重定向,标准错误输出仍然可以输出到屏幕或其他地方。
- 可以通过 fprintf(stderr, …), fputs(…, stderr) 或 fputc(…, stderr) 写入数据。
文件位置指针
用来指示当前文件读写位置。
文件操作
文件的打开与关闭
- 文件的打开
在C语言中,文件的打开是通过fopen函数实现的。这个函数接受两个参数:文件名和打开模式。打开模式决定了文件的读写权限以及文件是否会被创建或截断。fopen函数的原型如下:
FILE *fopen(const char *filename, const char *mode);
//fopen函数调用后需要检测返回值,保证程序的健壮性
FILE* file = fopen("E:/text.txt","w");
if (file == NULL) {
fprintf(stderr, "Error opening source file: %s\n", file);
//或者用perror();也ok
return 1;
}
其中filename是要打开的文件的名称(文件路径),mode是一个字符串,指定了文件的打开方式。
- 文件的关闭
文件关闭是通过fclose函数实现的,它接受一个FILE类型的指针作为参数,该指针是由fopen函数返回的。调用fclose函数会关闭与之关联的文件,并释放所有相关资源。fclose函数的原型如下:
int fclose(FILE *stream);
如果文件关闭成功,fclose返回0;如果发生错误,返回非零值。
文件路径
- 绝对路径:文件的在磁盘中的实际路径。
FILE* file = fopen("E:/VSfile/Project/test.txt", "w");
- 相对路径:相对于程序运行位置的路径。可用“./”表示相对路径的开始,也可省略。
FILE* file = fopen("test.txt", "w");
或
FILE* file = fopen("./test.txt", "w");
文件路径分隔符
- Windows: 使用反斜杠(\)作为分隔符。例如,“C:\Users\Username\Documents\file.txt”。
- UNIX/Linux/macOS: 使用正斜杠(/)作为分隔符。例如,“/home/username/Documents/file.txt”。
- 注意:在C语言字符串中,反斜杠(\)有特殊意义,用作转义字符。因此,在Windows文件路径中,需要用==两个反斜杠(\)==来表示一个实际的反斜杠。
跨平台文件路径处理: - 通用方法:使用正斜杠(/)作为分隔符,因为它在大多数操作系统中都是可接受的。
特定于平台的方法:可以定义宏来选择适当的分隔符。例如,定义 PATH_SEPARATOR 宏,在Windows中设为反斜杠(\),在其他系统中设为正斜杠(/)。
常用的文件打开模式
模式 | 含义 | 说明 |
---|---|---|
r | 只读 | 文件必须存在,否则打开失败 |
w | 只写(覆盖写) | 若文件存在,则清除原文件内容后写入;否则,创建文件后写入 |
a | 追加只写 | 若文件存在,则位置指针移到文件末尾,在文件尾部追加写入,故该方式不删除原文件数据;若文件不存在,则创建文件并追加写入 |
r+ | 读写 | 文件必须存在。在只读 r 的基础上加 + 表示增加可写的功能 |
w+ | 读写 | 在只写 w 的基础上加 + 表示增加可读的功能 |
a+ | 读写 | 在 a 模式的基础上,增加可读功能 |
rb | 二进制读 | 功能同模式 r ,区别:b 表示以二进制模式打开 |
wb | 二进制写 | 功能同模式 w 。二进制模式 |
ab | 二进制追加 | 功能同模式 a 。二进制模式 |
rb+ | 二进制读写 | 功能同模式 r+ 。二进制模式 |
wb+ | 二进制读写 | 功能同模式 w+ 。二进制模式 |
ab+ | 二进制读写 | 功能同模式 a+ 。二进制模式 |
读写 相关函数
字符串的写入与读出
getc / putc 函数 , fscanf / fprintf 函数 , fgets / fgets 函数 , 只能用于操作 文本文件 ;
函数名 | 用途 | 语法 | 示例 |
---|---|---|---|
fputc | 写入单个字符到文件 | int fputc(int c, FILE *stream); | fputc('A', file); |
fgetc | 从文件读取单个字符 | int fgetc(FILE *stream); | int ch = fgetc(file); |
fputs | 写入字符串到文件 | int fputs(const char *s, FILE *stream); | char str[] = "Hello\n"; fputs(str, file); |
fgets | 从文件读取一行文本 | char *fgets(char *s, int _MaxCount, FILE *stream); | char line[100];fgets(line, 100, file); |
fprintf | 格式化写入数据到文件 | int fprintf(FILE *stream, const char *format, ...); | fprintf(file, "Hello, %s!", "world"); |
fwrite | 写入数据块到文件 | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); | char data[] = "Binary data";fwrite(data, sizeof(char), strlen(data), file); |
- 读字符串函数fgets
fgets() 函数用来从指定的文件中读取一个字符串,并保存到字符数组中,它的用法为:
char* fgets (char* _Buffer,int _MaxCount,FILE* _Stream);
.buffer为字符数组
·maxcount为要读取的字符数量(不要超过buffer字符数组的大小)
·stream 文件指针
返回值:
读取成功时返回字符数组首地址,也就是buffer;读取失败时返回NULL;如果开始读取时文件内部指针已经指向了文件末尾,那么将读取不到任何字符,也返回 NULL.
·需要重点说明的是,在读取到MaxCount-1个字符之前如果出现了换行,或者读到了文件末尾,则读取结束。这就意味着,不管 MaxCount的值多大,fgets()最多只能读取一行数据,不能跨行。在C语言中,没有按行读取文件的函数,我们可以借助fgets(),将 MaxCount的值设置地足够大,每次就可以读取到一行数据。
用fgets函数读取整个文件
char buff[20];
while (feof(file)==0)
{
fgets(buff, 20, file);
printf("%s", buff);
}
- 写字符串函数fputs
返回0表示成功,否则表示失败返回错误信息。
if (feof(file)) {
printf("End of file reached.\n");
}
文件的格式化读写
函数名 | 用途 | 语法 | 特点/用途 |
---|---|---|---|
fprintf | 格式化写入数据到文件 | int fprintf(FILE *stream, const char *format, ...); | 类似于 printf ,但目标是文件也可是标准输出。 |
fscanf | 从文件格式化读取数据 | int fscanf(FILE *stream, const char *format, ...); | 类似于 scanf ,输入流较灵活。 |
printf | 格式化输出到标准输出 | int printf(const char *format, ...); | 用于将格式化的数据输出到标准输出(通常是屏幕)。 |
scanf | 从标准输入格式化读取数据 | int scanf(const char *format, ...); | 用于从标准输入(通常是键盘)读取格式化的数据。 |
二进制文件的读写
fread / fwrite 函数 既可以操作 二进制文件 , 又可以操作 文本文件 ; 但在打开对应文件时中文文本大概率乱码 乱码详解——CSDN
解决:若用记事本打开可以另存为选择ANSI保存就不会乱码了。
fgets()有局限性,每次最多只能读取文件的一行数据,如果想要读取多行内容,需要使用fread()函数。写入类似,对应使用fwrite。
函数名 | 用途 | 语法 |
---|---|---|
fwrite | 从指定内存缓冲区中写入若干字节数据到文件 | size_t fwrite(void const* _Buffer , size_t _ElementSize ,size_t _ElementCount ,FILE* _Stream ) |
fread | 从文件中读取若干字节数据到指定内存缓冲区中 ; | size_t fread( void* _Buffer ,size_t _ElementSize ,size_t _ElementCount , FILE* _Stream ) |
- fwrite()与fread()
对参数的说明:
- Buffer为内存区块的指针,它可以是数组、变量、结构体等。fread()中的 Bufer用来存放读取到的数据,fwrite() 中的 Bufer用来存放要写入的数据。
- ElementSize:表示每个数据块的字节数。
- ElementCount:表示要谈写的数据块的块数。
- Stream:表示文件指针。
。理论上,每次读写 size*count 个字节的数据
返回值:返回成功读写的块数,也即count,如果返回值小于count:
。对于 fwrite() 来说,肯定发生了写入错误,可以用ferror()函数检测,
。对于 fread() 来说,可能读到了文件末尾,可能发生了错误,可以用 ferror()或 feof() 检测,
fread\fwrite细节讲解_b站
fread函数的具体用法与实例(推荐)
随机读写
函数名 | 用途 | 语法 |
---|---|---|
rewind | 用于将位置指针移动到文件开头 | void rewind(FILE* Stream); |
fseek | 用于将位置指针移动到特定位置 | int fseek(FILE *Stream, long offset, int origin); |
ftell | 返回给定流 stream 的当前文件位置(可用于计算文件大小) | long int ftell(FILE *stream) |
参数说明:
- offset为偏移量,也就是要移动的字节数。(offset为正,向origin位置后移动。为负,向前)
- origin为起始位置(偏移量的基准点)
- fseek()返回0表示成功,非零表示失败。
C语言规定了三种起始位置,分别有对应常量
起始点 | 常量名 | 常量值 |
---|---|---|
文件开头 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件末尾 | SEEK_END | 2 |
文件拷贝
字符串拷贝与二进制文件拷贝
教程
介绍了main函数argv参数的用法,配合上二进制读写函数实现图片拷贝。
演示代码_CSDN
状态判断 相关函数
函数名 | 用途 | 语法 |
---|---|---|
feof | 检查文件是否到达文件末尾 | int feof(FILE *stream); |
- feof()
用途: feof 函数用于检查文件流是否已经到达文件末尾。End Of File
语法: int feof(FILE *stream);
返回值: 如果文件流已经到达文件末尾,则返回非零值;否则返回0。
错误的检查与输出 相关函数
函数名 | 用途 | 语法 |
---|---|---|
perror | 打印错误消息 | void perror(const char *s); |
ferror | 检查文件流错误状态 | int ferror(FILE *stream); |
-
perror()
用途: perror 函数用于打印一个错误消息到标准错误输出(通常是终端),并且它还会打印出与错误相关的系统错误号及其描述。
语法: void perror(const char *s);
参数: s 是一个字符串,通常包含一些上下文信息,比如文件名或者操作名称。 -
ferror()
用途: ferror 函数用于检查上一次对文件流的操作是否产生了错误。
语法: int ferror(FILE *stream);
返回值: 如果上一次操作产生错误,则返回非零值;否则返回0。
两个函数可以结合使用
如:
if (ferror(file)) {
perror("Error writing to file");
}
重定向
- 重定向输入:一般用scanf从键盘读取,也可从文件读取如: main.exe <test.txt (这里<可以看作文件流动的方向,从文件到程序)
- 重定向输出:一般用printf想屏幕输出,也可向文件写入:main.exe >test.txt
还可用freopen函数进行重定向。
详解重定向