目录
一、系统调用
1.1open函数
1.2close函数
1.3read函数
1.4write函数
1.5lseek函数
二、文件IO和标准IO的区别
三、标准库函数
3.1fopen函数
3.2fclose函数
3.3gets、fgets函数
3.4puts、fputs函数
3.5fread函数
3.6fwrite函数
3.7fseek函数
一、系统调用
1.1open函数
#include <fcntl.h>//指定权限打开文件(没有文件可以加mode参数创建的同时设置文件权限)
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode); @param: pathname 文件名的字符串 eg. “open.c”flags 常规的有 O_RDONLY可读、O_WRONLY可写、O_RDWR可读可写 //三选一mode O_CREAT 文件不存在则创建文件 同时需要设置mode参数 eg. 0666;文件存在的话也不影响O_EXCL 与O_CREAT连用时,若文件存在则出错返回-1 (可用来判断文件是否存在)O_APPEND 追加模式打开文件,之后对文件的读写光标都定位在文件尾O_TRUNC 文件原来有内容则截断,清空内容打开目标文件@return:成功则返回该文件的文件描述符file descriptor 简称fd,它是一个非负整数失败返回-1 (文件不存在且参数没加0_CREAT 或 文件存在但O_EXCL与O_CREAT连用)
文件描述符,范围(3~1023),0、1、2(默认已使用)分别对应标准输入stdin(键盘)、标准输出stdout(显示器屏幕)、标准错误stderr三个标准IO
创建函数还有一个单独的函数 int creat(filename,mode) mode的值有S_IRUSR 可读 、S_IWUSR 可写、S_IXUSR 可执行 、S_IRWXU 可读可写可执行 ,但用的少,原因是它只创建不打开
1.2close函数
#include <unistd.h>//关闭已打开的fd,成功返回0,出错返回-1
int close(int fd);
1.3read函数
#include <unistd.h>//从文件中读count个字节到buf
//成功返回读到的字节数,出错返回-1
ssize_t read(int fd, void *buf, size_t count);
1.4write函数
#include <unistd.h>//写buf到文件,写count个字节
//成功返回写入的字节数,出错返回-1
ssize_t write(int fd,const void *buf, size_t count);
1.5lseek函数
#include <sys/types.h>
#include <unistd.h>//修改已打开文件的输入偏移量
off_t lseek(int fd, off_t offset, int whence);@param: whenceSEEK_SET 距文件开始offset个字节SEEK_CUR 当前位置加offset个字节 offset可正可负SEEK_END 距文件末尾加offset个字节 offset可正可负
@return:成功则返回距文件开头的字节数出错返回-1
经常用于重置文件读写指针,还可用于计算文件大小 int size = lseek(fdsrc,0,SEEK_END)
二、文件IO和标准IO的区别
-
系统调用是操作系统提供的接口函数,如open、close是linux系统下的文件IO/低级IO,换成别的系统就用不了了,所以移植性差。我们写的代码得依靠内核里的驱动来让设备工作,系统调用是内核给用户提供的接口,通过把数据传输给接口才能调用驱动
-
标准C库函数不受限于操作系统的类型,更通用,移植性好,如fopen、fclose也能打开关闭文件,称为标准IO/高级IO
-
它们显著区别就在于标准IO有缓冲区,而文件IO没有缓冲区。
-
通过文件IO读写文件时,每次操作都涉及系统调用(用户态和内核态切换),好处是直接读写实际文件,坏处是频繁地系统调用会增加系统开销,
-
而标准IO可以看做是文件IO地基础上封装了缓冲机制,数据先被读入或写入缓冲区,只有缓冲区满或者主动调用fflush刷新缓冲区,才会进行实际的系统调用。这种方式减少了系统调用的次数,从而提高了性能。
-
三、标准库函数
不同于文件IO使用文件描述符(非负整数)来操作文件,标准IO使用文件流指针,使用上的区别只是定义的变量需要注意一下。
3.1fopen函数
#include <stdio.h> //指定权限打开文件
FILE* fopen(const char *pathname, const char *mode);param: path "filename"mode "r"只读打开 "r+"读写打开 注意这种方式打开,文件必须存在!!"w"只写打开 "w+"读写打开 同时w、w+ 打开文件后,都会清空文件!!,文件不存在则创建"a"只写打开 "a+"读写打开 和w、w+的区别是,它不清空,而是追加方式写!!return:成功返回文件流指针,出错返回NULL
通过fopen创建的文件权限是666 rw-rw-rw-
错误信息相关的处理函数:
//第一种比较常用,下面一种了解即可
void perror(const char *s) //先输出字符串s,再输出对应的错误信息
char strerror(int error)//根据错误号errno返回对应错误信息,errno系统自动生
3.2fclose函数
#include <stdio.h> //关闭文件
int fclose(FILE *stream);//成功返回1,失败返回EOF并设置errno
3.3gets、fgets函数
#include <stdio.h> //从键盘获取字符串到s指定位置
char *gets(char*s)//从文件流中获取n字节到string指定位置,也可用于获取键盘输入stdin
//成功返回字符串,到文件末尾或出错返回NULL
char *fgets( char *string, int n, FILE *stream );
区别:gets只能从标准输入(键盘)中读,不能指定长度(可能造成越界)
gets不将换行符读入,fgets则会读入换行符!!!
此外,fgets使用过程会出现两种情况:
遇到换行符'\n'停止读取,读回的内容包括换行符!!!因此捕获特定字符串需要手动清除,如string[strlen(string)-1] = '\0';
直到n-1个字节时还未遇到换行符,则返回n-1个字节然后末尾补空字符
3.4puts、fputs函数
#include <stdio.h> //打印字符串s
int puts(constchar *s)//输出string指定内容到文件流,可用于打印到显示窗口stdout,
//成功返回非负整数,出错返回EOF
int fputs( const char *string, FILE *stream );
区别:puts只能向标准输出中写
puts打印时自动添加换行符,fputs则不会添加,需要自行添加或者利用fflush(stdout)立刻刷新缓冲区
3.5fread函数
#include <stdio.h>//从文件流中读n个字节到ptr指定位置中
//size表示每个数据单元的大小 n表示数量
//成功返回读写个数,出错返回EOF
size_t fread(void *ptr, size_t size, size_t n, FILE *fp);
3.6fwrite函数
#include <stdio.h>//写ptr指定内容到文件流中,大小为n字节
//size表示每个数据单元的大小 n表示数量
//成功返回读写个数,出错返回EOF
size_t fwrite(const void *ptr, size_t size, size_t n, FILE *fp);
注意事项:
读写文件流,文件流指针自动后移
所以文件写完后,文件流指针指向文件末尾,再读,读不出来内容
解决办法可以是关闭再打开文件流,或者利用下面的定位
3.7fseek函数
#include <stdio.h>//定位文件流指针,距whence偏移offset
long fseek(FILE *stream, long offset, int whence)param: whence SEEK_SET、SEEK_CUR、SEEK_END
注意:
以"a"模式(追加)打开的文件,fseek无效
rewind()可以将文件流指针定位到文件开