打开流 fopen 、freopen和fdopen函数
转载 2015-12-21 14:13:07
fopen 、freopen和fdopen函数作用都是打开一个标准I/O流的,但是它们有一些略微的差别。从函数原型、函数描述、特殊用法。
一、函数原型
FILE *fopen(const char *restrict pathname, char *restrict type);
FILE *fdopen(int fd, const char *type);
FILE *freopen(const char *restrict pathname,const char *restrict type,FILE *restrict fp);
返回值,若成功,返回文件指针,若失败,返回NULL
mode 参数类型
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
字符 含义
────────────────────────────
"r" 打开文字文件只读
"w" 创建文字文件只写
"a" 增补, 如果文件不存在则创建一个
"r+" 打开一个文字文件读/写
"w+" 创建一个文字文件读/写
"a+" 打开或创建一个文件增补
"b" 二进制文件(可以和上面每一项合用)
"t" 文这文件(默认项)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━
文件使用方式 意 义
“rt” 只读打开一个文本文件,只允许读数据
“wt” 只写打开或建立一个文本文件,只允许写数据
“at” 追加打开一个文本文件,并在文件末尾写数据
“rb” 只读打开一个二进制文件,只允许读数据
“wb” 只写打开或建立一个二进制文件,只允许写数据
“ab” 追加打开一个二进制文件,并在文件末尾写数据
“rt+” 读写打开一个文本文件,允许读和写
“wt+” 读写打开或建立一个文本文件,允许读写
“at+” 读写打开一个文本文件,允许读,或在文件末追加数 据
“rb+” 读写打开一个二进制文件,允许读和写
“wb+” 读写打开或建立一个二进制文件,允许读和写
“ab+” 读写打开一个二进制文件,允许读,或在文件末追加数据
二、函数描述
1、fopen函数:打开路径名为pathname的一个指定的文件
2、fdopen函数:打开已存在的文件描述符,使标准I/O流与该文件相结合。主要用于fopen不能打开的特殊文件(如管道和网路通信等),这时必须先调用设备专用函数以获得一个文件描述符,然后在用fdopen使一个标准I/O与该文件描述符相结合。
3、Freopen函数:在指定的流上打开一个指定的文件,如若该流已经打开,则先关闭该流。若该流已经定向,则使用freopen清除该定向。简单的说可以利用freopen函数重定向。此函数一般用于将一个指定的文件代开为一个预定义的流:stdout,stdin,stderr。可以利用freopen将标准流冲定向。不要在程序的一开始就使用freopen。因为标准输出流(标准输入流和标准错误输出流)是常量,是不可再分配文件描述符的。
三、特殊用法
1、fopen
在指定w或a类型创建一个新文件时,无法是么该文件的访问权限位,所以在mode参数中不能有r类型。
2、fdopen
(1)在man手册中指出fdopen中的mode参数必须与fd原先的mode参数相匹配。这就是说这时的mode参数是原先mode参数的子集。否则会发生段错误。eg
#include
#include
#include
#include
//fdopen 中的mode的参数必须与参数fd的原先的读写权限相匹配
//参数mode 是fd原先读写权限的子集
int main(void)
{
int fd = -1;
int set = -1;
FILE *fp;
//fd = open("./text", O_RDWR | O_APPEND);//no
fd = open("./text", O_WRONLY | O_APPEND);//ok
//fd = open("./text", O_RDONLY | O_APPEND);//no
write(fd, "text", strlen("text"));
printf("22222\n");
fp = fdopen(fd, "w");
set = ftell(fp);
printf("11111\n");
write(fileno(fp), "qwer", strlen("qwer"));
printf("set = %d\n", set);
exit(0);
}
(2)在man手册中指出fdopen返回的文件指针的偏移量与参数文件描述符fd一致。eg:
#include
#include
#include
#include
#include
//fdopen 返回的fp的文件偏移量是 参数fd的偏移量。
int main(void)
{
int fd = -1;
int set = -1;
FILE *fp;
fd = open("./text", O_RDONLY);
lseek(fd, 0, SEEK_END);
fp = fdopen(fd, "r");
set = ftell(fp);
printf("set = %d\n", set);
exit(0);
}
(3)把原先error和end-of-file标志位清除,所以这时fdopen中的参数type为”w”或”w+”,不会造成截断文件长度。也就是说不会从文件开头写,会追加到现在偏移量之后。eg:
#include
#include
#include
#include
#include
//因为在使用fdopen时,已经把error和end-of-file标志位清除了,所以"w"和"w+"不会截断文件,新写入的数据会追加原先文件的结尾。
int main(void)
{
int fd = -1;
int set = -1;
FILE *fp;
fd = open("./text", O_WRONLY);
lseek(fd, 0, SEEK_END);
fp = fdopen(fd, "w");
write(fileno(fp), "fdopen", strlen("fdopen"));
set = ftell(fp);
printf("set = %d\n", set);
exit(0);
}
3、freopen重定向,如果这个流(参数fp指向的流)是打开的,则这个流将关闭。所以重新使用这个流时得重新打开。但这个流是标准输入/输出/错误输出流时,在调用freopen后重新打开将会比较麻烦。要借助于fgetpos/fsetpos和dup/dup2函数。下一遍详细介绍。