对标准IO的理解:
个人理解,如果有错误请指出
- c语言标准IO通过一个
FILE
结构来封装了read
和write
系统调用,并且标准IO缓冲区的分配也是通过修改FILE
的元素来改变, - 由于常用
stdin
,stdout
,就认为缓冲区是分为输入缓冲区和输出缓冲区的,这只是因为缓冲区承担一项工作(输入or输出)
如果用文件流以O_RDWR
状态打开一个文件,那么缓冲区将会同时作为输入和输出的缓冲区,
看一段代码cppreference
/* fflush example */
#include <stdio.h>
char mybuffer[80];
int main()
{
FILE * pFile;
pFile = fopen ("example.txt","r+");
if (pFile == NULL) perror ("Error opening file");
else {
fputs ("test",pFile);
//fflush (pFile); // flushing or repositioning required
fgets (mybuffer,80,pFile);
puts (mybuffer);
fclose (pFile);
return 0;
}
}
-
取消缓冲区刷新,那么缓冲区的数据不会写入
pFile
指向的文件,注释掉fflush(pFile),然后编译运行查看结果.发现待写入
pFile
的数据仍在缓冲区中,且这一部分占据了从流中读入数据的对应部分,fclose
函数在文件被关闭之前,冲洗缓冲区的输出数据,缓冲区中的任何输入数据被丢弃。于是留在缓冲区中待写入
pFile
的数据最终被写入文件, -
开启缓冲区刷新(在输出之后输入之前刷新缓冲区),编译运行,
写入的数据写入后,读入缓冲区的数据仍被占用???,
原因(推测):
在
fputs
执行完之后fflush
执行之前.此时缓冲区(也称为流)的读写位置是fputs
写入缓冲区的长度,那么fgets
读入的数据只能从这个地方开始,
对比文件流和内存流来理解标准IO
内存流(把内存当做文件用)
#include <stdio.h>
#include "apue.h"
static char buf[] = "ttest file";
int main(int argc,char *argv[]) {
int len = strlen(buf);
// 打开流的模式,即打开文件的模式
FILE *fp = fmemopen(buf,len,"r+");
if (fp == NULL) {
printf("get file error\n");
exit(1);
}
char ch;
// 把内存当做文件用,从内存(文件)中读入字符到标准IO的缓冲区,然后提取出来
while ((ch = fgetc(fp)) != EOF) {
printf("%c",ch);
}
return 0;
}
- 通过下面来理解内存流和文件流的差别,然后理解标准IO
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BSZ 48
char buf[BSZ];
int main(int argc,char *argv[]) {
FILE *fp;
// 1
memset(buf,'a',BSZ - 2);
buf[BSZ - 2] = '\0';
buf[BSZ - 1] = 'X';
// 打开文件流
if ((fp = fmemopen(buf,BSZ,"w+")) == NULL) {
printf("fmemopen error");
exit(1);
}
// stdout打印缓冲区
printf("initial buffer content: %s\n",buf);
// 打开水龙头,向文件(内存)中写入,但此时只是停留在标准IO的缓冲区中,
fprintf(fp,"hello,world");
printf("before standard buffer flush: %s\n",buf);
// fflush强制IO缓冲区的数据写入fp指定的文件中,fmemopen保证了文件是内存
fflush(fp);
printf("after fflush: %s\n",buf);
printf("len of string in buf = %ld\n",(long)strlen(buf));
//2
memset(buf,'b',BSZ - 2);
buf[BSZ - 2] = '\0';
buf[BSZ - 1] = 'X';
// 向fp指向的文件写入数据,但是还停留在IO库的缓冲区中
fprintf(fp,"hello, world");
// reposition会导致缓冲区被flush
fseek(fp,0,SEEK_SET);
// 此时buf应该都为 b
printf("after fseek: %s\n",buf);
printf("len of string in buf = %ld\n",(long)strlen(buf));
memset(buf,'c',BSZ - 2);
buf[BSZ - 2] = '\0';
buf[BSZ - 1] = 'X';
// 流的读写位置通过seek定位到了0,fclose之前会flush缓冲区,
fprintf(fp,"hello,world");
// 关闭流之前,io库自动刷新所有的IO库的缓冲区
fclose(fp);
printf("after fclose: %s\n",buf);
printf("len of string in buf = %ld\n",(long)strlen(buf));
return 0;
}
流和文件相关联,那么每个进程默认的3个std流引用的是哪3个文件?
- 引用的是
STDIN_FILENO、STDOUT_FILENO、STDERR_FILENO
这3个文件描述符所引用的文件
流其实就是文件,标准IO库在操作系统的IO例程上封装.FILE*
指向的结构用来描述流的信息:缓冲区长度,缓冲区地址,打开的文件描述符等?
- 一般用于将一个指定的文件打开为一个预定的流(文件->流),
把流看做水龙头的开关更好理解,普通流则水来自磁盘文件,内存流则水来自内存
ISO C 2011
标准中gets
弃用,那么最好也不要使用puts
来源:CSDN
作者:_llc
链接:https://blog.csdn.net/qq_43580151/article/details/104111576