Linux:输入输出与文件操作函数学习笔记整理

导言
在 C 语言的编程世界里,输入输出以及文件操作是与外界交互、处理数据存储的重要环节。scanf
、printf
、open
、fopen
、read
、fread
、write
、fwrite
、fseek
、lseek
、mmap
这些函数各司其职,共同构建起强大的数据处理体系。本文将详细介绍这些函数的功能、用法、示例,并进行对比分析。
一、标准输入输出函数:scanf 与 printf
1. printf 函数及其变体
printf
函数是 C 标准输入输出库(stdio.h
)中用于格式化输出的函数,其原型为int printf(const char *format, ...)
。其中,format
是格式控制字符串,包含普通文本和格式说明符;...
表示可变参数列表。
1 | #include <stdio.h> |
在上述代码中,%d
、%f
、%s
分别对应十进制整数、浮点数、字符串的输出格式,将变量的值以指定格式输出到标准输出流(通常是终端)。
格式说明符
格式说明符 | 功能描述 | 示例 |
---|---|---|
%d |
输出带符号的十进制整数 | printf("%d", 10); 输出 10 |
%f |
输出浮点数(默认保留 6 位小数) | printf("%f", 3.14); 输出 3.140000 |
%.nf |
输出浮点数并指定保留 n 位小数 | printf("%.2f", 3.1415926); 输出 3.14 |
%s |
输出以空字符\0 结尾的字符串 |
printf("%s", "Hello"); 输出 Hello |
printf
还有两个重要变体:
fprintf
函数:用于将格式化数据输出到指定文件,原型为int fprintf(FILE *stream, const char *format, ...)
。
1 | #include <stdio.h> |
sprintf
函数:将格式化数据写入字符数组,原型为int sprintf(char *str, const char *format, ...)
。
1 | #include <stdio.h> |
2. scanf 函数及其变体
scanf
函数用于从标准输入设备(通常是键盘)读取格式化数据,原型为int scanf(const char *format, ...)
。与printf
不同,scanf
的可变参数列表需要传入变量的地址,通过指针实现数据写入。
1 | #include <stdio.h> |
上述代码通过%d
格式说明符读取整数,并使用&num
获取变量num
的地址,将输入的数据存储到num
中。
scanf
的变体:
fscanf
函数:从指定文件流中读取格式化数据,原型为int fscanf(FILE *stream, const char *format, ...)
。
1 | #include <stdio.h> |
sscanf
函数:从字符串中解析格式化数据,原型为int sscanf(const char *str, const char *format, ...)
。
1 | #include <stdio.h> |
二、文件操作函数:open、fopen、read、fread、write、fwrite、fseek、lseek、mmap
1. 文件打开函数:open 与 fopen
open 函数
open
是 UNIX/Linux 系统下的底层文件操作函数,在``头文件中声明,原型如下:
1 | #include <sys/types.h> |
其中,pathname
是文件路径名,flags
指定打开方式(如O_RDONLY
只读、O_WRONLY
只写、O_RDWR
读写),mode
在创建新文件时指定权限。
1 | #include <stdio.h> |
上述代码以只读方式打开test.txt
文件,若失败通过perror
输出错误信息。
fopen 函数
fopen
是 C 标准库提供的高层文件操作函数,在``中声明,原型为FILE *fopen(const char *filename, const char *mode)
。其中,filename
是文件名,mode
指定打开模式(如"r"
只读、"w"
只写、"a"
追加写)。
1 | #include <stdio.h> |
该代码以只写模式打开test.txt
文件,若失败输出错误信息。
2. 文件读取函数:read 与 fread
read 函数
read
是与open
配套的底层文件读取函数,原型为ssize_t read(int fd, void *buf, size_t count)
。其中,fd
是open
返回的文件描述符,buf
是数据缓冲区,count
是期望读取的字节数。
1 | #include <stdio.h> |
上述代码从test.txt
文件读取数据到buffer
缓冲区并打印。
fread 函数
fread
是 C 标准库的文件读取函数,原型为size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
。其中,ptr
是缓冲区指针,size
是每个数据项大小,nmemb
是数据项数量,stream
是fopen
返回的文件指针。
1 | #include <stdio.h> |
此代码从二进制文件people.dat
中读取Person
结构体数据。
3. 文件写入函数:write 与 fwrite
write 函数
write
是底层文件写入函数,原型为ssize_t write(int fd, const void *buf, size_t count)
。其中,fd
是文件描述符,buf
是待写入数据缓冲区,count
是写入字节数。
1 | #include <stdio.h> |
上述代码向test.txt
文件写入字符串数据。
fwrite 函数
fwrite
用于向文件写入数据,原型为size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
。
1 | #include <stdio.h> |
该示例将Person
结构体数据写入二进制文件people.dat
。
4. 文件定位函数:fseek 与 lseek
fseek 函数
fseek
是 C 标准库中的文件定位函数,用于设置文件指针的位置,原型为int fseek(FILE *stream, long int offset, int whence)
。其中,stream
是fopen
返回的文件指针,offset
是偏移量,whence
指定起始位置(SEEK_SET
文件开头、SEEK_CUR
当前位置、SEEK_END
文件末尾) 。
1 |
|
上述代码以读写模式打开文件,使用fseek
将文件指针移动到末尾,并追加新的文本内容。
lseek 函数
lseek
是 UNIX/Linux 系统下的底层文件定位函数,原型为off_t lseek(int fd, off_t offset, int whence)
。其中,fd
是open
返回的文件描述符,offset
和whence
含义与fseek
类似 。
1 |
|
上述代码通过lseek
实现文件指针的底层定位,可用于后续的读写操作。
5. 内存映射函数:mmap
mmap
是 UNIX/Linux 系统下用于内存映射的函数,它可以将文件内容映射到内存区域,实现高效的数据访问。其原型为void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
。其中,addr
指定映射的起始地址(通常设为NULL
由系统分配),length
是映射的字节数,prot
指定内存保护模式(如PROT_READ
可读、PROT_WRITE
可写),flags
指定映射标志(如MAP_SHARED
共享映射),fd
是文件描述符,offset
是文件内的偏移量 。
1 |
|
上述代码通过mmap
将文件内容映射到内存,直接修改内存中的数据,实现高效的文件数据修改,最后通过munmap
解除映射。
三、函数对比与总结
功能分类 | 函数名 | 特点与应用场景 | 注意事项 |
---|---|---|---|
标准输出 | printf |
格式化输出到标准输出流(通常为终端),支持 % d、% s 等格式控制符,用于实时展示程序运行结果。 | 输出缓存可能导致数据延迟显示,可使用fflush(stdout) 强制刷新;格式控制符需与参数类型匹配。 |
fprintf |
格式化输出到指定文件流,用于持久化存储结构化数据,如日志文件或配置文件写入。 | 文件指针需提前通过fopen 打开,且注意文件打开模式对写入权限的影响。 |
|
sprintf |
将格式化数据写入字符数组,常用于动态生成字符串(如拼接 URL、格式化时间戳)。 | 目标数组需确保足够大,避免缓冲区溢出;结果字符串以\0 结尾。 |
|
标准输入 | scanf |
从标准输入流(通常为键盘)读取格式化数据,通过变量地址传递结果,需注意输入验证。 | 容易引发缓冲区溢出(如%s 不限制长度),推荐使用fgets 结合sscanf 替代。 |
fscanf |
从文件流中解析格式化数据,适用于读取结构化文件(如 CSV、配置文件)。 | 需配合fopen 打开文件,注意文件指针位置及读取失败时的错误处理。 |
|
sscanf |
从字符串中提取格式化数据,常用于文本分析或协议解析(如解析 HTTP 请求头)。 | 源字符串必须以\0 结尾,支持%n 等特殊控制符获取读取字符数。 |
|
文件打开 | open |
底层系统调用,返回文件描述符(整数),支持设置文件权限、O_CREAT/O_RDWR 等标志位。 | 底层系统调用,返回文件描述符(整数),支持设置文件权限、O_CREAT/O_RDWR 等标志位。 |
fopen |
高层文件操作函数,返回文件指针(FILE* ),支持r 、w 、a 等简易模式及缓冲机制。 |
返回NULL 时需检查errno 判断错误原因(如文件不存在、权限不足)。 |
|
文件读取 | read |
基于文件描述符的底层读取操作,按字节读取数据,常用于高性能、非格式化文件读取。 | 需手动计算读取字节数,适合处理二进制文件,不支持文本模式转换。 |
fread |
从文件流中读取指定长度的数据块,适用于读取结构体、数组等二进制数据。 | 需指定数据项大小及数量,返回实际读取的项数,可能因文件尾或错误中断。 | |
文件写入 | write |
基于文件描述符的底层写入操作,按字节写入数据,常用于高效写入二进制文件。 | 需处理返回值判断写入成功字节数,注意文件描述符可写权限。 |
fwrite |
向文件流写入指定长度的数据块,适合写入结构体、数组等二进制数据。 | 需指定数据项大小及数量,写入失败时检查ferror 获取错误信息。 |