标准I/O库之打开流、读写流和每次一行I/O

打开流

以下是三个打开一个标准I/O流的函数

#include <stdio.h>
FILE *fopen(const char *restrict pathname, const char *restrict type);
FILE *freopen(const char *restrict pathname, const char *restrict type, FILE * restrict fp);
FILE *fdopen(int fd, const char *type);
三个函数的返回值:若成功,返回文件指针;若出错,返回NULL

这三个函数的区别如下:

  • fopen函数打开路径名为pathname的一个指定的文件。

  • freopen函数在一个指定的流上打开一个指定的文件,若该流已经打开,则先关闭该流。若该流已经定向,则使用freopen清除该定向。此函数一般用于将一个指定的文件打开为一个预定义的流:标注输入、标准输出或标准错误。

  • fdopen函数取一个已有的文件描述符(此文件描述符可以从opendupdup2fcntlpipesocketsocketpairaccept 函数得到),并使一个标准的I/O流与该描述符相结合。此函数常用于创建管道和网络通信通道返回的文件描述符。因为这些特殊类型的文件不能用标准I/O函数fopen打开,所以必须先调用设备专用函数以获得一个文件描述符,然后用fdopen使一个标准I/O流与该描述符相结合。

    fopenfreopen是ISO C的所属部分。而ISO C并不涉及文件描述符,所以仅有POSIX.1具有fdopen

    type参数指定对该I/O流的读、写方式,ISO C规定type参数可以有15中不同的值。如下表所示:

type 说明 open(2)标志
r 或 rb 为读而打开 O_RDONLY
w 或 wb 把文件截断至0长,或为写而创建 O_WRONLY | O_CREAT | O_TRUNC
a 或 ab 追加:为在文件尾写而打开,或为写而创建 O_WRONLY | O_CREAT | O_APPEND
r+ 或 r+b 或 rb+ 为读和写而打开 O_RDWR
w+ 或 w+b 或 wb+ 把文件截断至0长,或为读和写而打开 O_RDWR | O_CREAT | O_TRUNC
a+ 或 a+b 或 ab+ 为在文件尾读和写而打开或创建 O_RDWR | O_CREAT | O_APPEND

type参数中将b作为其一部分时,这使得标准I/O系统可以区分文本文件和二进制文件。因为UNIX内核并不对这两种文件进行区分,所以在UNIX系统环境下指定字符b作为type的一部分实际上并无作用。

对于fdopen函数,type参数的意义有些不同。fdopen函数不能为写而截断其打开的任一文件。除此之外,标准I/O追加写方式也不能用于创建该文件。

扫描二维码关注公众号,回复: 9294842 查看本文章

当以读和写类型打开一个文件时,具有下列限制。

  • 如果中间没有fflushfseekfsetposrewind,则在输出的后面不能直接跟随输入。
  • 如果中间没有fseekfsetposrewind,或者一个输入操作没有到达文件尾端,则在输入操作之后不能直接跟随输出。

调用fclose函数来关闭一个打开的流。

#include <stdio.h>
int fclose(FILE *fp);
返回值: 若成功,返回 0;若出错,返回EOF

读和写流

一旦打开了流,则可在三种不同非格式化I/O中进行选择,对其进行读、写操作。

  1. 每次一个字符的I/O。一次读或写一个字符,如果流是带缓冲的,则标准I/O函数处理所有缓冲。

  2. 每次一行的I/O。若想要进行一行读或写,则使用fgetsfputs。每行以换行符终止。

  3. 直接I/O。freadfwrite函数支持这种类型的I/O。

    直接I/O在ISO C中被称之为二进制I/O、一次一个对象I/O、面向记录的I/O或面向结构的I/O。

1.输入函数

以下是3个函数可用于一次读一个字符。

#include <stdio.h>
int getc(FILE *fp);
int fgetc(FILE *fp);
int getchar(void);
3个函数返回值:若成功,返回下一个字符;若已到达文件末尾或出错,返回EOF

不管是出错还是到达文件末尾,这3个函数都返回同样的值,为了区分这两种不同的情况,必须调用ferrorfeof

#include <stdio.h>
int ferror(FILE *fp);
int feof(FILE *fp);
上面两个函数返回值:若成功,返回非0;否则,返回0
void clearerr(FILE *fp);

在大多数实现中,为每个流在FILE对象中维护了两个标志:

  • 出错标志
  • 文件结束标志。

调用clearerr可以清除这两个标志。

从流中读取数据以后,可以通过ungetc将字符再压送回流中。

#include <stdio.h>
int ungetc(int c, FILE *fp);
函数返回值: 若成功,返回c; 若出错,返回EOF

​ 用ungetc压回字符时,并没有将它们写到底层文件中或设备上,只是将它们写回标准I/O库中的流缓冲区中.

2. 输出函数

既然有输入函数就会有对应的输出函数。

#include <stdio.h>
int putc(int c, FILE *fp);
int fputc(int c, FILE *fp);
int putchar(int c);
三个函数返回值: 若成功,返回c; 若出错,返回 EOF

putchar(c)等同于putc(c, stdout)putc可被实现为宏,而fputc不能实现为宏。

每次一行I/O

下面函数提供每次输入一行的功能。

#include <stdio.h>
char *fgets(char *restrict buf, int n, FILE *restrict fp);
char *gets(char *buf);
这两个函数返回值:若成功,返回buf;若已到达文件末尾出错,返回NULL

注意: gets函数是极其不安全,容易造成缓冲区溢出的问题;强烈推荐使用fgets函数来进行读入一行的操作。

fputsputs提供每次输出一行的功能。

#include <stdio.h>
int fputs(const char *restrict str, FILE *restrict fp);
int puts(const char *str);
两个函数返回值: 若成功,返回非负值;若出错,返回EOF

puts函数将一个以null字节终止的字符串写到标准输出,终止符不写出。但是puts函数随后将一个换行符写到标准输出。fputs将一个以null字节终止的字符串写到指定的流,尾端的终止符不写出。虽然puts函数没有像gets函数那样的安全问题,但是还是应避免使用它,以免需要记住最后是否有添加一个换行符。如果总是使用fgetsfputs,需要明确每行终止处的必须处理换行符。

测试示例如下:

#include "../../include/apue.h"                                                 
#define MAXSIZE 100                                                             
void test1(){                                                                   
     char buf[MAXSIZE] = {0};                                                    
     while(fgets(buf, MAXSIZE, stdin) != NULL){                                  
         printf("buf = ");                                                       
         fputs(buf, stdout);                        
     }                                                                           
 } 
int main()                                                                      
{                                                                               
    test1();                                                                    
    return 0;                                                                   
}       

结果图如下:

发布了229 篇原创文章 · 获赞 17 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40073459/article/details/104380129