系统调用IO函数open,close等都是围绕着文件描述符fd进行相关操作的。
当打开一个文件时,即返回一个文件描述符,然后该文件描述符就用于后续的IO操作。
open系列函数 | fopen系列函数 |
---|---|
常用于打开设备文件 | 常用于打开普通文件 |
可以指定要创建文件的访问权限 | 不能指定要创建文件的访问权限 |
open返回一个文件描述符 | fopen返回一个文件指针 |
利用文件描述符操纵文件 | 利用文件指针操作文件 |
POSIX系统调用 | ANSI C库函数 |
低层次IO | 高层次IO,对open的扩展和封装 |
只能在POSIX操作系统上移植 | 可移植到任何操作系统 |
非缓冲IO | 带缓冲IO |
只能读取二进制或普通文本 | 可以读取一个结构 |
而当用C库标准IO函数(fopen、fclose、fread、fwrite、fseek等)打开或创建一个文件时,我们已使一个==流(FILE *stream)==与一个文件相关联了。
fopen打开流
FILE *stream, 文件指针,FILE结构体又被称作流。
#include <stdio.h>
/** @description : 打开一个文件* @param - path : 指定文件路径,如:"./test.txt"* @param - mode :指定文件的打开方式,如下图:* @return : 成功,返回指向该文件的文件指针; 若失败,返回 NULL*/
FILE *fopen(const char *path, const char *mode);
mode参数:
mode | 说明 |
---|---|
“r” | 打开文本文件用于读 |
“w” | 创建文本文件用于写,并删除已存在的内容(如果有的话) |
“a” | 添加;打开或创建文本文件用于在文件末尾写 |
“rb” | 打开二进制文件用于读 |
“wb” | 创建二进制文件用于写,并删除已存在的内容(如果有的话) |
“ab” | 添加;打开或创建二进制文件用于在文件末尾写 |
“r+” | 打开文本文件用于更新(即读和写) |
“w+” | 创建文本文件用于更新,并删除已存在的内容(如果有的话) |
“a+” | 添加;打开或创建文本文件用于更新和在文件末尾写 |
"rb+“或"r+b” | 打开二进制文件用于更新(即读和写) |
"wb+“或"w+b” | 创建二进制文件用于更新,并删除已存在的内容(如果有的话) |
"ab+“或"a+b” | 添加;打开或创建二进制文件用于更新和在文件末尾写 |
当打开一个流时,标准IO函数fopen返回一个指向FILE对象的指针( 文件指针)。
该对象通常是一个结构,它包含了标准IO库为管理该流需要的所有信息(流),
包括用于实际IO 的文件描述符、指向用于该流缓冲区的指针、缓冲区的长度、当前在缓冲区中的字符数以及出错标志等。
为了引用一个流,需将FILE 指针作为参数传递给每个标准IO函数。
fclose关闭流
#include <stdio.h>
/** @description : 关闭一个已打开的流* @param - stream :文件指针(流)* @return : 成功,返回0; 若失败,返回EOF*/
int fclose(FILE *stream); //stream指定的是要关闭的流(文件指针)
//成功返回0;若出错,返回EOF
在该文件被关闭之前,冲洗缓冲中的输出数据。
缓冲区中的任何输入数据被丢弃。如果标准I/O库已经为该流自动分配了一个缓冲区,则释放此缓冲区。
当一个进程正常终止时(直接调用exit函数,或从main函数返回),
则所有带未写缓冲数据的标准IO流都被冲洗,所有打开的标准IO流都被关闭。
fwrite对打开的流写入
#include <stdio.h>
/** @description : 对已打开的流进行写入数据块* @param - ptr :指向 数据块的指针* @param - size :指定写入的每个数据项的字节数,如调用sizeof(char)* @param - nmemb : 指定写入的数据项的个数* @param - stream :要写入的文件流* @return : 返回实际写入的数据项的个数*/
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
fread对打开的流进行读取
#include <stdio.h>
/** @description : 对已打开的流进行数据读取* @param - ptr :指向 数据块的指针* @param - size :指定读取的每个数据项的字节数* @param - nmemb : 指定要读取的数据项的个数* @param - stream :要读取的文件流* @return : 返回实际读取数据项的个数;*/
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
fwrite、fread不能区分文件结尾和错误,调用者必须使用feof函数和ferror函数来确定发生了什么。恩…
fseek定位流
#include <stdio.h>
/** @description : 重定位文件指针位置* @param - stream :指定重定位文件指针* @param - offset :指定偏移量,整数表示正向偏移,负数表示负向偏移* @param - whence : 指定偏移基准位置,如:宏SEEK_CUR(当前位置)、 SEEK_END(文件结尾) 或 SEEK_SET(文件开头)* @return : 成功,返回0; 若失败,返回-1,且不改变指针位置。*/
int fseek(FILE *stream, long offset, int whence);
demo.c
#include <stdio.h>
#include <string.h>int main(void)
{
FILE *fp = NULL; int ret;char *str = "hello chenchenchen";char readBuf[128] = {
0};fp = fopen("./test.txt", "a+");if(fp == NULL){
printf("Can't fopen file\n");return -1;}printf("fopen file success\n");ret = fwrite(str, sizeof(char),strlen(str),fp);printf("fwrite byte = %d\n",ret);ret = fseek(fp,0,SEEK_SET); if(ret == 0)printf("fseek success\n");ret = fread(readBuf,sizeof(char),strlen(str),fp);printf("fread byte=%d, readBuf= %s\n",ret,readBuf);ret = fclose(fp);if(ret < 0){
printf("Can't fclose file\n");return -1;}printf("fclose file success\n");fp = NULL; /* 防止游离指针 */return 0;
}
cxx@ubuntu16:~/C/9_io$ gcc demo.c
cxx@ubuntu16:~/C/9_io$ ./a.out
fopen file success
fwrite byte = 18
fseek success
fread byte=18, readBuf= hello chenchenchen
fclose file success
流定向
对于ASCII字符集,一个字符用一个字节表示。对于国际字符集,一个字符可用多个字节表示。
标准I/O文件流可用于单字节或多字节(“宽")字符集。
流的定向(stream’s orientation)决定了所读、写的字符是单字节还是多字节的。
当一个流最初被创建时,它并没有定向。
如若在未定向的流上使用一个多字节I/O函数(见<wchar.h>),则将该流的定向设置为宽定向的。
若在未定向的流上使用一个单字节IO函数,则将该流的定向设为字节定向的。
只有两个函数可改变流的定向。
fwide函数可用于设置流的定向;freopen 函数清除一个流的定向。
#include <wchar.h>
//返回值:若流是宽定向的,返回正值;若流是字节定向的,返回负值;若流是未定向的,返回0
int fwide(FILE *stream, int mode);
mode参数:
如若mode参数值为负,fwide将试图使指定的流是字节定向的.
如若mode参数值为正,fwide 将试图使指定的流是宽定向的(多字节)。
如若mode参数值为0, fwide将不试图设置流的定向,但返回标识该流定向的值。
#include <stdio.h>
FILE *freopen(const char *path, const char *mode, FILE *stream);
freopen函数:在一个指定的流上打开一个指定的文件,
如若该流已经打开,则先关闭该流。若该流已经定向,则使用freopen清除该定向。
此函数一般用于将一个指定的文件打开为一个预定义的流: 标准输入、标准输出或标准错误。
实现重定向,把预定义的标准流文件定向到由path指定的文件中。
path: 指定存储输入输出的自定义文件路径文件名。
mode:指定文件打开方式。
stream:stdin标准输入、stdout标准输出或stderr标准错误,也对应了最前面的三个文件描述符(0,1,2)。
#include <stdio.h>
FILE *fdopen(int fd, const char *mode);
fdopen函数取一个已有的文件描述符,并使一个标准的IO流与该描述符相结合,转换为对应的文件指针后返回。
mode字符串参数则代表着文件指针的流形态,此形态必须和原先文件描述词读写模式相同。
此函数常用于由创建管道和网络通信通道函数返回的描述符。因为这些特殊类型的文件不能用标准IO函数 fopen 打开,
所以我们必须先调用设备专用函数以获得一个文件描述符,然后用fdopen使一个标准IO流与该描述符相结合。