说明:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
QQ 群 号:513683159 【相互学习】
内容来源:
菜鸟教程-stdio.h、C语言中文网、百分网-C语言的文件概念、博客园-FILE结构体、知乎-一切皆文件、博客园-Linux-struct file
具体函数使用细节看上面参考来源网站。
概念
1️⃣什么是文件?
①文件就是保存数据的一种机制。
数据:一连串字符(字符序列)组成。
②Linux思想:一切皆文件。即:所有东西都可通过文件的形式单方面的访问/呈现(不是文件也以文件规范访问,但不可反向创建)。
好处:省心(统一操作,简化接口)。
2️⃣什么是文件流?
前提知识:
磁盘:数据(文件)存储不丢失的地方。 内存:处理数据的地方。
字符集:ASCII字符集:一字符一个字节。 国际字符集:一字符多字节
文件流:文件在磁盘与内存之间传递的过程。
输入流:从磁盘到内存的过程。 输出流:从内存到磁盘的过程。
流定向:决定所读、写字符是单字节还是多字节。【freopen()
:清除流定向,fwide()
设置流定向】
故:打开文件就到打开一个流(流提供了文件和程序的通信通道)。
3️⃣如何描述文件?
C语言中定义一个存储文件流信息的对象:FILE
库变量。
FILE
结构体:由系统定义的结构体,含有文件相关信息,如:文件名、文件状态、当前读写位置、文件描述符等。
文件描述符:操作系统数组(打开文件列表的索引)。每个数组元素包含一个文件控制块(FCB, File Control Block),操作系统用它来管理特定的文件。
FILE *fp
:文件指针(file pointer):指向文件,通过它对文件进行各种操作(找到对应文件信息结构体变量,再根据结构体变量找到该文件实施对文件的操作)。
4️⃣如何操作文件?
一般步骤:打开文件 --> 读写文件 --> 关闭文件。
打开文件:建立和文件的关系。【文件指针指向FILE
结构体变量】
读写文件:
多种读写方式;
1.一个字符。2.若干字节。3.一整行。
读写位置灵活:
1.文件头。2.文件中。
关闭文件:断开和文件的关系。【文件指针断开FILE
结构体变量,禁止文件操作】
5️⃣三个标准流
stdin
:标准输入、stdout
标准输出、stderr
标准出错。
6️⃣缓冲
目的:减少IO函数调用次数
类型:【setbuf()
打开或关闭缓冲,setvbuf()
设置指定缓冲类型】
①全/块缓冲:填满缓冲区后才进行IO操作(flush:将缓冲区内容写到磁盘上)。
②行缓冲:遇见换行符时才进行IO操作(涉及终端一般为行缓存:stdin,stdout)
③不带缓冲:不对字符进行缓冲存储。(stderr)
函数介绍
一、缓冲文件流
1️⃣ setbuf()、setbuffer() 、setlinebuf()、setvbuf()—— 流缓冲操作
#include <stdio.h>
void setbuf(FILE *stream, char *buf); /定义流stream应如何缓冲。该函数应在与流stream相关的文件被打开时,且还未发生任何输入或输出操作之前被调用一次
void setbuffer(FILE *stream, char *buf, size_t size); /定义流 stream 应如何缓冲。
void setlinebuf(FILE *stream);
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
stream :文件流 buf:缓冲区 size:缓冲区大小 mode:模式
return:成功返回0,失败返回非0并设置errno
mode选项:
_IONBF
:unbuffered——不带缓冲
_IOLBF
:line buffered——行缓冲
_IOFBF
: fully buffered——全缓冲
2️⃣ fflush() ——冲洗流
#include <stdio.h>
int fflush(FILE *stream); /强制写入给定输出或更新流的所有用户空间缓冲数据。
stream :文件流
return:成功回0。否则返回EOF,并设置errno指示错误。
3️⃣fwide() ——设置和确定FILE流的方向
#include <wchar.h>
int fwide(FILE *stream, int mode); /设置和确定FILE流的方向
stream :文件流 mode :模式
mode:正数-》宽字节,负数-》单字节,0-》未决定
注意:fwide()
不改变已定向流的定向,一旦流有了方向,它就不能被更改并一直保持到流关闭。
二、操作文件流
1️⃣ fopen()、fdopen()、freopen()——打开流
#include <stdio.h>
FILE *fopen(const char *pathname, const char *mode);
FILE *fdopen(int fd, const char *mode);
FILE *freopen(const char *pathname, const char *mode, FILE *stream);
pathname:文件路径名 mode:模式 fd:文件描述符 stream:文件流
return:指向FILE结构体指针(指向该文件信息保存的结构体中),若打开失败则返回空指针。
fopen()
:以mode
方式打开filename
指向的文件,同时将文件相关信息存到FILE文件表中[文件表]
.
fdopen()
:获取现有文件描述符fd
,并使标准IO流与该描述符相结合。
freopen()
: 从指定流stream
上打开filename
指向的文件,若流已打开则先关闭,若流已定向则清除。【常用于指定文件打开预定义的流:标准输入、标准输出、标准出错】
mode
:由 r(read,读)、w(write,写)、a(append,追加)、t(text,文本文件)、b(binary,二进制文件)、+(读和写) 六个字符拼成.
注意事项:
①"r"的文件必须存在。
②“a”文件不存在则创建,存在则追加。
③"w"文件不存在则创建,存在则删除在创建。
④"t"与b":并无本质区别,只是对换行符的处理不同。
2️⃣ fclose() —— 关闭流
#include <stdio.h>
int fclose(FILE *fp) /刷新stream指向的流(使用fflush(3)写入任何缓冲的输出数据),并关闭底层的文件描述符。
fp: 指向FILE对象的指针,该FILE对象指定了要被关闭的流。
return:关闭成功返回0,失败返回EOF
三、读写文件流:
三种类型的非格式化I/O操作
序号 | 类型 | 函数 | 注意 |
---|---|---|---|
1️⃣ | 每次一个字符的I/O | getc()、fgetc()、getchar() fputc() 、putc() 、putchar() | 若流带缓冲则会处理所有缓冲 |
2️⃣ | 每次一行的I/O | gets() 、fgets() puts() 、fputs() | 每行以换行符终止,且注意最大行长 |
3️⃣ | 直接I/O | fread() fwrite() | 每次读写某种数量对象,每个对象具有指定长度 |
1️⃣ fgetc() 、getc() 、getchar()——输入字符
#include <stdio.h>
int fgetc(FILE *stream); /从流中读取下一个字符,并将其作为无符号字符转换为int型,或在文件结束或错误时返回EOF。
int getc(FILE *stream); /与fgetc()是等价的,除了它可以被实现为一个宏,对流进行多次计算。
int getchar(void); /等价于gettc (stdin)。
stream:文件流
return:文件或错误结束时返回读取为unsigned char类型的字符,并将其转换为int或EOF类型。
1️⃣ fputc() 、putc() 、putchar()——输出字符
#include <stdio.h>
int fputc(int c, FILE *stream); /将转换为unsigned char的字符c写入流。
int putc(int c, FILE *stream); /与fputc()是等价的,除了它可以被实现为一个对流进行多次计算的宏。
int putchar(int c); /putchar(c)等价于putc(c, stdout)。
c:符号 stream:文件流
return:返回以unsigned char形式写入的字符,并将其转换为int型或EOF型
2️⃣ gets() 、fgets() ——输入字符串
#include <stdio.h>
char *gets(char *s); /从stdin中读取一行到s所指向的缓冲区中,直到出现结束的换行符或EOF,并用空字节('\0')替换。
char *fgets(char *s, int size, FILE *stream); /最多从流中读取一个小于size的字符,并将其存储到s所指向的缓冲区中。在EOF或换行符之后停止读取。如果读取了换行符,则将其存储到缓冲区中。一个终止的空字节('\0')被存储在缓冲区的最后一个字符之后。
s:缓冲区 size:字节大小 stream:文件流
return:成功返回s,在错误时返回NULL或在文件结束时没有读取字符。
2️⃣ puts() 、fputs() —— 输出字符串
#include <stdio.h>
int puts(const char *s); /将字符串s和末尾的换行符写入标准输出。
int fputs(const char *s, FILE *stream); /将字符串s写入流,而不将其终止为空字节('\0')。
s:字符串 stream:文件流
return:成功时返回一个非负数,出错时返回EOF。
3️⃣ fread() —— 输入二进制流[必须以"b"形式打开文件]
#include <stdio.h>
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); /从stream指向的流中读nmemb数据项,每个数据项大小为size字节长,并将它们存储在ptr给出的位置。
ptr:存储空间 size:字节大小 nmemb:数据项数 stream:文件流
return:若成功将返回读取的条目数。条目数等于仅当size为1时传输的字节数。若发生错误或到文件末尾,则返回值是一个短项计数(或0)。
3️⃣ fwrite() —— 输出二进制流[必须以"b"形式打开文件]
#include <stdio.h>
size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream); /将大小为size字节长的nmemb数据项写入到stream所指向的流中,从ptr给出的位置获取它们
ptr:存储空间 size:字节大小 nmemb:数据项数 stream:文件流
return:若成功将返回写入的条目数。条目数等于仅当size为1时传输的字节数。若发生错误或到文件末尾,则返回值是一个短项计数(或0)。
四、定位文件流
rewind()——设置文件位置为开头
相当于:(void) fseek(stream, 0L, SEEK_SET)
#include <stdio.h>
void rewind(FILE *stream); /为流所指向的流设置文件位置指示器到文件的开头
stream:文件流
三种方法定位IO流
序号 | 类型 | 函数 | 注意 |
---|---|---|---|
1️⃣ | 偏移量为长整型 | fseek():设置流位置 ftell() :获取流位置 | |
2️⃣ | 偏移量为off_t型 | ftello() fseeko() | |
3️⃣ | 文件位置用fpos_t表示 | fgetpos() fsetpos() |
fseek() 、ftell() 、ftello() 、fseeko() 、fgetpos() 、fsetpos()—— 设置/获取文件流位置
#include <stdio.h>
int fseek(FILE *stream, long offset, int whence); /设置流所指向的流的文件位置指示器。
long ftell(FILE *stream); /获取流所指向的流的文件位置指示器的当前值
int fseeko(FILE *stream, off_t offset, int whence); /等价于fseek()
off_t ftello(FILE *stream); /等价于ftell()
int fsetpos(FILE *stream, const fpos_t *pos); /等价于fseek()
int fgetpos(FILE *stream, fpos_t *pos); /等价于ftell()
stream:文件流 offset:偏移量 whence:位置标志
return:fseek()/fseeko()返回0,而ftell()/ftello()返回当前偏移量。否则返回-1并设置errno表示错误。
whence参数:
起始位置 | 常量名 | 常量值 |
文件开头 | SEEK_SET | 0 |
当前位置 | SEEK_CUR | 1 |
文件末尾 | SEEK_END | 2 |
五、格式化I/O
1️⃣格式化输入
#include <stdio.h>
int scanf(const char *format, ...); /输入字符串,并将字符序列转换成指定类型变量
int fscanf(FILE *stream, const char *format, ...);
int sscanf(const char *str, const char *format, ...);
format:格式控制字符串 ...:参数列表。 stream:文件流 str:存储空间
#include <stdarg.h>
int vscanf(const char *format, va_list ap);
int vsscanf(const char *str, const char *format, va_list ap);
int vfscanf(FILE *stream, const char *format, va_list ap);
格式说明([]表示可选部分):
%[*][fldwidth][lenmodefier]convtype
(1)* 用于抑制转换。按转换说明的其余部分对输人进行转换,但转换结果并不存放在参数中。
(2)fldwidth:说明最大宽度(即最大字符数)。
(3)lenmodifier:说明要用转换结果初始化的参数大小。
convtype 转换类型
2️⃣格式化输出
#include <stdio.h>
int printf(const char *format, ...); /将格式化数据写到标准输出
int fprintf(FILE *stream, const char *format, ...); /将格式化数据写到指定文件流
int dprintf(int fd, const char *format, ...); /将格式化数据写到指定文件描述符
int sprintf(char *str, const char *format, ...); /将格式化数据写到指定数组str,自动加null,。但该字节不包括在返回值中
int snprintf(char *str, size_t size, const char *format, ...); /将格式化数据写到指定数组str,并设置缓冲区长度
format:格式控制字符串 ...:参数列表。 stream:文件流 fd:文件描述符 str:存储空间
#include <stdarg.h>
int vprintf(const char *format, va_list ap);
int vfprintf(FILE *stream, const char *format, va_list ap);
int vdprintf(int fd, const char *format, va_list ap);
int vsprintf(char *str, const char *format, va_list ap);
int vsnprintf(char *str, size_t size, const char *format, va_list ap);
格式说明([]表示可选部分):
%[flags][fldwidth][precision][lenmodefier]convtype
(1)flag:标识
-:在字段内左对齐输出
+;总是显示带符号转换的符号
空格:若第一个字符不是符号,则在其前面加上一个空格
#:指定另一种转换形式
0:添加前导0(而非空格)进行填充
(2)fldwidth:说明转换的最小字段宽度。
(3)precision:说明整型转换后最少输出数字位数、浮点转换后小数点后的最少位数,字符串转换后的最大字符数。
(4)lenmodefier:参数长度
hh 有符号或无符号的char
h 有符号或无符号的short
l 有符号或无符号的long或者宽字符
11 有符号或无符号的long long
j intmax_t或uintmax t
z size_t
t ptrdiff_t
L long double
convtype 转换类型
六、检测文件
clearerr() 、feof() 、ferror()、fileno()——检查和重置文件流状态
#include <stdio.h>
void clearerr(FILE *stream); /清除由stream指向的流的文件结束符和错误指示符。
int feof(FILE *stream); /(检查文件是否处于结束位置)测试stream所指向的流的文件结束指示器,如果设置了该指示器,则返回非零值。文件结束指示器只能由clearerr()函数清除。
int ferror(FILE *stream); /(检查文件读写时是否出错)测试stream所指向的流的错误指示符,如果设置了,则返回非零值。错误指示符只能由clearerr()函数重置。
int fileno(FILE *stream); /检查参数流并返回用于实现该流的整型文件描述符。文件描述符仍然归stream所有,当调用fclose(3)时将被关闭。在将文件描述符传递给可能关闭它的代码之前,使用dup(2)复制它。
stream:文件流
return:clearerr()这不会失败....其他当位置指针为文件结束标识符则返回非零,否则返回零.
七、临时文件
tmpfile() ——创建临时文件
#include <stdio.h>
FILE *tmpfile(void) /以二进制读写模式(wb+)创建临时文件,在流关闭的时或程序终止的时自动删除。
return:若成功返回一个指向被创建的临时文件的流指针。若文件未被创建,则返回NULL。
tmpnam()——为临时文件取名
#include <stdio.h>
char *tmpnam(char *s); /产生一个与现有文件名不同的一个有效名字符串 /因此具有此名称的文件在某个时间点不存在,因此无知的程序员可能会认为它适合用于临时文件。如果参数s为NULL,则在内部静态缓冲区中生成此名称,并可能被下一次调用tmpnam()所覆盖。如果s不为NULL,名称被复制到s所指向的字符数组(长度至少为L_tmpnam),如果成功则返回s的值。
char *tempnam(const char *dir, const char *pfx); /允许调用者所产生路径名指定目录和前缀。 返回一个指向一个字符串的指针,该字符串是一个有效的文件名,因此当tempnam()检查时,带有此名称的文件不存在。生成的路径名的文件名后缀将以pfx开头,以防pfx是一个最多5个字节的非null字符串。生成的路径名的目录前缀部分需要是“适当的”(通常至少意味着可写)。
s:字符串
return:返回一个指向字符串的指针,该字符串是一个有效的文件名