一、标准I/O概念
标准IO是一个标准函数包和stdio.h头文件中定义的,不依赖于系统内核,所以移植性强。
1.流的概念
在c语言中所有的IO操作只是简单的从程序移进或移出字节的工作(可以将数据的输出和输入看作是数据的流入和流出),这中字节流被称为流(stream)。
2.FILE对象
文件IO函数的操作都是依赖文件描述符,打开一个文件时,就返回一个文件描述符,然后该文件描述符用于后续相关的IO操作。标准IO库的操作依赖于流(stream)进行。打开一个文件就会创建一个FILE对象,此对象是一个结构体。
1>流的分类
a.文本流:在流处理过程中,所有数据以字符形式出现。所有字符以ASCII形式存储。
b.二进制流:在流处理过程中把数据当成二进制序列。
例:文本流:2021 -> 50 48 50 49
二进制流:2021 -> 00000111 11100101
2>一个进程启动时会打开三流stdin、stdout、stderr(标准输入,输出,错误流)
3.标准IO的文件缓冲
1>缓冲区
文件IO:读写文件时,每次操作都会执行相关系统调用,好处是直接读写实际文件,坏处是频繁的系统的调用会增加系统开销。
标准IO:系统自动的在内存中为每一个正在使用的文件开辟一个缓冲区,从内存向磁盘输出数据必须先送到缓冲区,装满缓冲区在一起送到磁盘中。
从磁盘中读数据,则一次从磁盘文件将一批数据读入到内存缓冲区中,然后再从缓冲区逐个的将数据送到程序的数据区。
【注】标准I/O可以看成在文件I/O的基础上由标准I/O库封装并维护了缓冲机制(流缓冲,都在用户空间)
避免频繁地呼叫系统调用,尽量减少使用read/write的调用;其次缓冲区大小的设置在不同OS上是有技术的,标准库为我们做了优化选择。
2>缓冲类型(3种)
**全缓冲区**:这种缓冲区要求填满整个缓冲区后才进行I/O系统调用操作。
对于磁盘文件通常使用全缓冲区访问。
第一次执行I/O 操作时,ANSI 标准的文件管理函数通过调用malloc 函数获得需使用的缓冲区。linux默认大小为4096。
**行缓冲区**:在这种情况下,当在输入和输出中遇到换行符时,执行IO系统调用操作。
当流涉及一个终端时(例如标准输入和标准输出),使用行缓冲区。
因为标准I/O 库每行的缓冲区长度是固定的,只要填满了缓冲区,即使还没有遇到换行符也将执行I/O 系统调用操作。默认行缓冲区大小为1024 字节。
**无缓冲区**:标准I/O 库不对字符进行缓存,即对流的读写操作会立即操作实际文件。
很多的人机交互界面要求不可全缓存。
标准出错流stderr通常是不带缓冲区的,这使得出错信息能够尽快地显示出来。
【注】1)不同类型设备导致关联的FILE流采用不同的缓冲类型
2)不同缓冲类型的缓冲大小
3)标准IO内部malloc的过程,实际使用时才会申请。
二、相关函数
1.fopen()函数,fclose()函数
#include <stdio.h>
FILE *fopen(const char *path, const char *mode);
参数1:文件路径名
2:文件打开模式
FILE *fdopen(int fd, const char *mode);//需要与文件描述符相结合
FILE *freopen(const char *path, const char *mode, FILE *stream);//常用于流的重定向
int fclose(FILE *fp);//关闭打开的文件
2.输入/输出相关函数
输入相关:
#include <stdio.h>
//从一个指定的流中读取一个字符
int fgetc(FILE *stream);
int getc(FILE *stream);
【注】如果使用getc()函数读取一个字符时发现是文件结尾,它将返回一个特殊值EOF.
事例:
int ch; //用int类型存储EOF
FILE *fp;
fp = fopen("test.txt","r");
ch = getc(fp); //获取初始输入
while((ch = getc(fp)) != EOF)
{
putchar(ch); //处理输入
}
//从一个指定的流中读取一个字符串
char *fgets(char *s, int size, FILE *stream);
char *gets(char *s);
//从stdin中读取一个字符
int getchar(void);
输出相关:
//向一个指定的流中输出一个字符
int fputc(int c, FILE *stream);
int putc(int c, FILE *stream);
//向stdout中输出一个字符。
int putchar(int c);
//输出字符串
int puts(const char *s);
int fputs(const char *s, FILE *stream);
程序示例,将一个文件的1/3复制到另一个文件
#include<stdio.h>
int main(int argc,const char *argv[])
{
if( 2 > argc)
{
printf("argument error!\n");
return -1;
}
int ch,count = 0;
FILE *in,*out;
if(NULL == (out = fopen(argv[1],"r")))
{
perror("fopen");
return -2;
}
if(NULL == (in = fopen(argv[2],"w")))
{
perror("fopen");
return -3;
}
while(EOF != (ch = getc(out)))
{
if((count++)%3 == 0)
{
if('\n' == ch)
{
count--;
}
putc(ch,in);
}
}
if(0 != fclose(in) || 0 != fclose(out))
{
fprintf(stderr,"fclose error!\n");
}
return 0;
}
运行结果: