C语言文件操作(文件流指针)
- 打开文件(fopen)
FILE* fopen(const char* path, const char* mode)
path: 需要打开文件的路径加上文件名称,可以不加路径,则默认打开当前路径下的文件
mode: 打开方式
r: 以读方式打开,如果文件不存在则报错
r+: 以读写方式打开,如果文件不存在则报错
w: 以写方式打开,如果文件不存在则创建,存在则将文件截断,即清空当前内容,文件流指针指向文件头部
w+: 以读写方式打开,如果文件不存在则创建,存在则将文件截断,即清空当前内容,文件流指针指向文件头部
a: 以写方式打开,如果文件不存在则创建,存在则在文件末尾继续添加
a+: 以读写方式打开,如果文件不存在则创建,存在则在文件末尾继续添加
返回值:打开成功,返回指向该文件的文件指针,打开失败,返回 NULL
- 读取文件(fread)
ssize_t fread(const void* ptr, size_t szie, size_t nmemb, FILE* stream)
ptr: 将读到的内容保存到 ptr 当中
size: 块的大小(单位是字节)
nmemb: 块的个数(该参数值的含义为数值)
size*nmemb = 字节,即一次读取的字节数
stream: 文件流指针,标志开始的位置
返回值:返回成功读取的块的个数
- 写入文件(fwrite)
ssize_t fwrite(const void* ptr, size_t szie, size_t nmemb, FILE* stream)
ptr: 将写的内容保存到 ptr 当中
size: 块的大小(单位是字节)
nmemb: 块的个数(该参数值的含义为数值)
stream: 文件流指针,标志开始的位置
返回值:返回成功写入的块的个数
- 文件流指针定位( fseek)
int fseek(FILE* stream, long offset, int whence)
stream: 文件流指针,标志开始的位置
offset: 偏移量,针对 whence 而言
whence:
SEEK_END
SEEK_SET
SEEK_CUR
返回值:当 offset 是向文件尾方向偏移的时候,无论偏移量是否超出文件尾,fseek 都是返回0;当 offset 是向文件头方向偏移的时候,如果 offset 没有超出文件头,是正常偏移,文件指针指向正确的偏移地址,fseek 返回值为 0,当 offset 超出文件头时,fseek 返回出错 -1,文件指针不变还是处于原来的地址
- 关闭文件(fclose)
int fclose(FILE* stream)
stream: 文件流指针
返回值:关闭成功返回 0,关闭失败返回 EOF(-1)
系统调用文件操作(文件描述符)
- open
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
成功:新打开的文件描述符
pathname: 要打开或创建的目标文件
flags: 打开文件时,可以传入多个参数选项,用下面的一个或者多个常量进行“或”运算,构成flags。
参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读写打开
mode:文件权限
O_CREAT : 若文件不存在,则创建它
O_TRUNC : 打开文件后,截断文件
O_APPEND: 追加写
返回值:成功则返回文件描述符,失败返回 -1
- 读取文件(read)
ssize_t read(int fd, const void* buf, size_t count)
fd: 文件描述符
buf: 读的位置
count: 最大可读字节,预留 \0 位置
返回值:返回成功读取的字节数
- 写入文件(write)
ssize_t write(int fd, const void* buf, size_t count)
fd: 文件描述符
buf: 写的位置
count: 最大可写字节
返回值:返回成功写入的字节数
- lseek
off_t lseek(int fd, off_t offset, int whence)
fd: 文件描述符
offset: 偏移量,针对 whence 而言
whence:
SEEK_END
SEEK_SET
SEEK_CUR
返回值:返回成功写入的字节数
- 关闭文件(close)
int fclose(int fd)
fd: 文件描述符
两种文件操作区别
fopen fclose fread fwrite fseek 都是C标准库当中的函数,我们称之为库函数(libc)
open close read write lseek 都属于系统提供的接口,称之为系统调用接口
所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发