Linux C高级编程——文件操作之库函数
宗旨:技术的学习是有限的,分享的精神是无限的
——为什么要设计标准I/O库?
直接使用API进行文件访问时,需要考虑许多细节问题
例如:read、write时,缓冲区的大小该如何确定,才能使效率最优
标准I/O库封装了诸多细节问题,包括缓冲区分配
——标准I/O库缓冲
标准I/O库提供缓冲的目的:尽可能减少使用read、write调用的次数,以提高I/O效率。
通过标准I/O库进行的读写操作,数据都会被放置在标准I/O库缓冲中中转。
——缓冲类型
—全缓冲
在填满标准I/O缓冲区后,才进行实际I/O操作(例如调用write函数)
调用fflush函数也能强制进行实际I/O操作
—行缓冲
在输入和输出遇到换行符时,标准I/O库执行I/O操作
因为标准I/O库用来收集每一行的缓存的长度是固定的,所以,只要填满了缓存,即使没有遇到新行符,也进行I/O操作
终端(例如标准输入和标准输出),使用行缓冲
—不带缓冲
标准I/O库不对字符进行缓冲存储
标准出错是不带缓冲的,为了让出错信息尽快显示出来
——流的定向
对于ASCII字符集,一个字符用一个字节表示
对于国际字符集,一个字符可用多个字节表示
流的定向决定了所读、写的字符是单字节还是多字节的
一、打开关闭文件
1、fopen
——用于打开一个指定的文件
(1)函数原型
#include<stdio.h>
FILE* fopen(const char *restrict pathname, const char *restrict type);
(2)参数
pathname:要打开的文件名
type:指定文件的读、写方式
r/rb——只读方式打开
w/wb——只写,不存在则创建,使文件长度为0
a/ab——追加
r+/r+b/rb+——读写打开
W+/w+b/wb+——使文件长度为0,读写而打开
a+/a+b/ab+——在文件尾读和写而打开或创建
(3)返回值
——FILE结构指针(open返回的是文件描述符)
2、fflush
——刷新一个流(强制标准I/O库进行系统调用,以将数据传递到内核)
(1)函数原型
int fflush(FILE *fp);
(2)函数参数
fp:文件指针;若fp=NULL,则刷新所有输出流
(3)返回值
成功返回0,出错返回EOF
3、fclose
——关闭一个打开了的流
(1)函数原型
int fclose(FILE *fp);
(2)函数参数和返回值
fp:要关闭的流对应的文件指针
(3)返回值
—成功返回0,出错返回EOF
在该文件被关闭之前,刷新缓存中的输出数据。缓存中的输入数据被丢弃,如果标准I/O库已经为该流自动分配了一个缓存,则释放此缓存。
二、读写文件流
1、字符读/写文件流
1.1、fgetc
——读出流中的一个字符
(1)函数原型
int fgetc(FILE *fp);
(2)函数参数
fp:文件指针
(3)返回值
成功返回读到的内容; 出错返回-1。
1.2、fputc
——写一个字符到文件流中
(1)函数原型
int fputc(int c, FILE *fp);
(2)函数参数
c:字符c
fp:文件指针
(3)返回值
成功返回内容; 出错返回-1
2、行读写文件流(一行一行进行)——不能操作二进制文件
2.1、fgets
——读出流中的一行字符串
(1)函数原型
char *fgets(char *s, int n, FILE *fp);
(2)函数参数
s:字符串指针,指向用来存储所得数据的地址
n:缓冲区大小
fp:文件指针
(3)返回值
成功返回读到的内容到s中; 出错返回NULL。
2.2、fputs
——写一行字符串到标准流中
(1)函数原型
int *fputs(char*s, FILE *fp);
(2)函数参数
s:以空字符结尾的字符串(后接换行符)写入标准流stdout中
fp:文件指针
(3)返回值
成功返回非负数; 出错返回-1。
3、块读写文件流 (fread/fwrite)
——每次I/O操作读写某种数量的对象,而每个对象具有指定的长度
例如,可读写一个二进制数组、结构
(1)函数原型
size_t fread(void *ptr, size_t size, size_t nobj, FILE *fp);
size_t fwrite(const void *ptr, size_t size, size_t nobj, FILE *fp);
(2)参数
第一个参数ptr:用于读写的缓冲区
第二个参数size:每个对象的大小
第三个参数nobj:要读写的对象个数
第四个参数fp:文件指针
(3)返回值
返回实际读/写的对象数
三、文件流定位
1、ftell
——用于获取当前文件偏移量
(1)函数原型
long ftell(FILE *fp);
(2)函数参数
fp:文件指针
(3)返回值
成功返回当前文件偏移量; 出错返回-1。
2、fseek
——用于设置当前文件偏移量
(1)函数原型:
int fseek(FILE *fp, long offset, int whence);
(2)函数参数
第一个参数fp:文件指针
第二个参数offset:相对偏移量:需结合whence才能计算出真正的偏移量
第三个参数whence:该参数取值是三个常量
SEEK_SET: 当前文件偏移量为:距文件开始处的offset个字节
SEEK_CUR: 当前文件偏移量为:当前文件偏移量+offset(可正可负)
SEEK_END: 当前文件偏移量为:当前文件长度+offset(可正可负)
(3)返回值
成功返回0,出错返回非0
3、rewind
—— 用于将文件偏移量设置到文件的起始位置
(1)函数原型
void rewind(FILE *fp);
(2)函数参数
fp:文件指针
(3)返回值
无
// 小程序:用标准库函数实现文件拷贝功能:
#include<stdio.h>
//#include<string.h>
#include<stdlib.h>void file_copy(char *fd, char *fp);int main(intargc, char **argv)
{file_copy(argv[1], argv[2]);return 0;
}void file_copy(char *fd, char *fp)
{FILE *from_fd, *to_fd;int ret, file_len; //定义文件大小char buffer[1024];//缓冲区if((from_fd = fopen(fd, "rb")) == NULL) //打开目标文件{printf("file openfail!\n");exit(1);}if((to_fd = fopen(fp, "wb")) == NULL) //创建新文件{printf("file openfail!\n");exit(0);}fseek(from_fd, 0L, SEEK_END);file_len = ftell(from_fd);//计算文件大小fseek(from_fd, 0L, SEEK_SET);if((ret = fread(buffer, file_len, 1, from_fd)) == -1) //读取文件到buffer中,返回实际读到的对象个数(不是读取的字节数){printf("file readfail!\n");exit(0);}//printf("!!!!!!!!!!!%d\n",ret);fwrite(buffer, file_len, 1, to_fd); //把buffer里面的内容写到新文件中fclose(from_fd);fclose(to_fd);//关闭文件
}