PILE读书笔记_标准I/O
在学习和分析标准I/O库的同时, 可以重点与Linux的I/O系统调用进行比较。
stdin、 stdout和stderr都是FILE类型的文件指针, 是由C库静态定义的, 直接与文件描述符0、 1和2相关联, 所以应用程序可以直接使用它们。其中,stdin是不可写的, stdout是不可读的, 而stderr不仅不可读, 且没有缓存。
I/O的缓存
C库的I/O接口对文件I/O进行了封装, 为了提高性能, 其引入了缓存机制, 共有三种缓存机制: 全缓存、 行缓存及无缓存。
(1)全缓存一般用于访问真正的磁盘文件。 C库会为文件访问申请一块内存, 只有当文件内容将缓存填满或执行冲刷函数flush时, C库才会将缓存内容写入内核中。
(2)行缓存一般用于访问终端。 当遇到一个换行符时, 就会引发真正的I/O操作。 需要注意的是, C库的行缓存也是固定大小的。 因此, 当缓存已满, 即使没有换行符时也会引发I/O操作。
(3)无缓存, 顾名思义, C库没有进行任何的缓存。 任何C库的I/O调用都会引发实际的I/O操作。
下面看一个行缓存的例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void)
{
printf("Hello ");
if ( == fork()) {
printf("child\n");
return ;
}
printf("parent\n");
return ;
}
执行结果如下:

之所以是这样的结果, 就是因为背后的行缓存。 执行printf( "Hello") 时, 因为printf是向标准输出打印的, 因此使用的是行缓存。 字符串Hello没有换行符, 所以并没有真正的I/O输出。 当执行fork时,子进程会完全复制父进程的内存空间, 因此字符串Hello也存在于子进程的行缓存中。 故而最后的输出结果中, 无论是父进程还是子进程都有Hello字符串。
fopen函数
# include<stdio.h>
FILE * fopen(const char * path,const char * mode)
参数说明:
(1)path:需要打开的文件路径
(2)mode:文件打开方式,主要对应下表
| mode | function |
|---|---|
| r | 以只读方式打开文件,该文件必须存在。 |
| r+ | 以可读写方式打开文件,该文件必须存在。 |
| rb+ | 读写打开一个二进制文件,允许读数据。 |
| rt+ | 读写打开一个文本文件,允许读和写。 |
| w | 打开只写文件,若文件存在则文件长度清为0,即该文件内容会消失。若文件不存在则建立该文件。 |
| w+ | 打开可读写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
| a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留。(EOF符保留) |
| a+ | 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。 (原来的EOF符不保留) |
| wb | 只写打开或新建一个二进制文件;只允许写数据。 |
| wb+ | 读写打开或建立一个二进制文件,允许读和写。 |
| wt+ | 读写打开或着建立一个文本文件;允许读写。 |
| at+ | 读写打开一个文本文件,允许读或在文本末追加数据 |
| ab+ | 读写打开一个二进制文件,允许读或在文件末追加数据。 |
fdopen函数
#include <stdio.h>
FILE *fdopen(int fd, const char *mode);
fdopen用于从文件描述符fd生成一个文件流FILE
fileno函数
#include <stdio.h>
int fileno(FILE *stream);
fileno则用于从文件流FILE得到对应的文件描述符
无论是fdopen还是fileno, 关闭文件时, 都要使用fclose来关闭文件, 而不是用close。 因为只有采用此方式, fclose作为C库函数, 才会释放文件流FILE占用的内存。
fread函数
size_t fread(void *buffer, size_t size, size_t count, FILE *file);
参数说明:
(1)buffer是读取数据后存放地址
(2)size是的块长度
(3)count是块的数量,实际读取长度为size*count,返回值为块成功读取块的count数量
fwrite函数
size_t fwrite(const void *buffer, size_t size, size_t count, FILE *file);
参数说明:
(1)buffer是写入数据后存放地址
(2)size是的块长度
(3)count是块的数量,实际读取长度为size*count,返回值为块成功写入块的count数量
下面看一个读写文件的例子:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char buf[];
int ret;
FILE *fp = fopen("./tmp.txt", "w+");
if (!fp) {
printf("Fail to open file\n");
return -;
}
ret = fwrite("", sizeof(""), , fp);
printf("we write %d member\n", ret);
memset(buf, , sizeof(buf));
ret = fread(buf, , , fp);
printf("We read %s, ret is %d\n", buf, ret);
fwrite("", sizeof(""), , fp);
fclose(fp);
return ;
}
运行结果:


为什么fread什么都没有读取到, 返回值是0呢? 因为每一次系统调用的read和write成功返回后, 文件的偏移量都会被更新 。fwrite和fread操作的是同一个文件指针fp, 也就是对应的是同一个文件描述符。 第一次fwrite后, 在tmp.txt中写入了字符串“123”, 同时文件偏移为3, 也就是到了文件尾。 进行fread操作时, 既然操作的是同一个文件描述符, 自然会共享同一个文件偏移, 那么, 从文件尾自然读取不到任何数据。
ferror函数
int ferror(FILE *stream);
若文件流出错则返回非0,否则返回0。ferror()函数常与clearerr()函数一起使用,如果ferror(fp)发现错误,返回一个非0值,那么调用clearerr(fp)后,ferror(fp)的值变为0。
当文件流读到文件尾时, 文件流会被设置上EOF标志。 即使不使用clearerr清除EOF标志, 有新的数据, 也可以读取成功,这是因为:文件流FILE的错误标志位只有在打开IO_DEBUG的情况下才会对后面的I/O调用产生影响: 在有错误标志位的时候, 后面的I/O调用都会直接返回EOF。 而一般情况下, IO_DEBUG这个宏是没有定义的。
getc函数
#include <stdio.h>
int fgetc(FILE *stream);
int getc(FILE *stream);
正常的情况下返回一个char,可以吗?
不可以,这些函数返回的字符是以unsigned char形式保存,然后转换为int的。因此,在int的值域里,有效的返回值总是一个正整数。例如,遇到文件结束时,返回宏EOF。通常EOF定义成-1,在int域里,-1是没有歧义的,我们不会迷惑到底是读进来了一个字符'0xff',还是遇到了EOF。而在char域里,这样的歧义是存在的。
PILE读书笔记_标准I/O的更多相关文章
- PILE读书笔记_文件I/O
open函数 int open(const char *pathname, int flags, mode_t mode); 参数说明: (1)pathname: 表示要打开的文件路径 (2)flag ...
- PILE读书笔记_进程环境
进程是操作系统运行程序的一个实例, 也是操作系统分配资源的单位. 在Linux环境中, 每个进程都有独立的进程空间, 以便对不同的进程进行隔离, 使之不会互相影响. atexit函数 #include ...
- PILE读书笔记_基础知识
程序的构成 Linux下二进制可执行程序的格式一般为ELF格式. 我们可以用readelf命令来读取二进制的信息. ELF文件的主要内容就是由各个section及symbol表组成的. 下面来分别介绍 ...
- 新标准C++程序设计读书笔记_继承和多态
简单继承的例子: #include <iostream> #include <string> using namespace std; class CStudent { pri ...
- 新标准C++程序设计读书笔记_运算符重载
形式 返回值类型 operator 运算符(形参表) { …… } 运算符重载 (1)运算符重载的实质是函数重载(2)可以重载为普通函数,也可以重载为成员函数 class Complex { publ ...
- 新标准C++程序设计读书笔记_类和对象
面向对象的程序设计方法 抽象:将某类客观事物共同特点(属性)归纳出来,形成一个数据结构(可以用多个变量描述事物的属性):将这类事物所能进行的行为也归纳出来,形成一个个函数,这些函数可以用来操作数据结构 ...
- C++ primer读书笔记 chapter3 标准库类型
除第二章介绍的是C++的基本类型,本章将大致介绍一下C++定义的内容丰富的抽象数据库类型标准库.着重介绍一下sting.vector和bitset. 3.2标准库string类型 1.string类型 ...
- 『TensorFlow』读书笔记_进阶卷积神经网络_分类cifar10_上
完整项目见:Github 完整项目中最终使用了ResNet进行分类,而卷积版本较本篇中结构为了提升训练效果也略有改动 本节主要介绍进阶的卷积神经网络设计相关,数据读入以及增强在下一节再与介绍 网络相关 ...
- 『TensorFlow』读书笔记_进阶卷积神经网络_分类cifar10_下
数据读取部分实现 文中采用了tensorflow的从文件直接读取数据的方式,逻辑流程如下, 实现如下, # Author : Hellcat # Time : 2017/12/9 import os ...
随机推荐
- NOIP 2015 跳石头
题目背景 一年一度的“跳石头”比赛又要开始了! 题目描述 这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石.组委会已经选择好了两块岩石作为比赛起点和终点.在起点和终点之间,有 N 块岩石(不 ...
- 【AC自动机】【动态规划】hdu2296 Ring
题解:http://www.cnblogs.com/swm8023/archive/2012/08/08/2627535.html 要输出路径,价值最大优先,价值相同的取长度较小者,仍相同取字典序较小 ...
- 【线段树】bzoj3038 上帝造题的七分钟2 / bzoj3211 花神游历各国
暴力修改,记录一段是否全部为1或0,若全是了,则不再修改. 注意3211一定要判是否为0,否则会T得惨无人道. #include<cstdio> #include<cmath> ...
- 【动态规划】【记忆化搜索】【dfs】bzoj2748 [HAOI2012]音量调节
f[i][j]表示第i首歌音量为j是否可能.若是将状态之间建边,那么答案就是max(j){f[i][j]==true&&0<=j<=limit}.于是就是图中dfs一遍判断 ...
- JDBC 操作数据库
jdbc: package org.java.dao; import java.sql.Connection; import java.sql.DriverManager; import java.s ...
- java读写文件及保留指定位小数
1)先上代码: public static void main(String[] args)throws IOException{ double[][] B=new double[1043][2102 ...
- 键盘事件OnKeyListener
1.效果图:就是在文本框中输入A,则显示A,输入B,则显示B.... (1)activity_main.xml <?xml version="1.0" encoding=&q ...
- Ubuntu 16.04通过源码安装QUEM虚拟机
下载编译安装: wget http://download.qemu-project.org/qemu-2.9.0.tar.xz tar xvJf qemu-2.9.0.tar.xz cd qemu-2 ...
- 狗日的Javascript中的闭包
前面的话: 闭包,是 javascript 中重要的一个概念,对于初学者来讲,闭包是一个特别抽象的概念,特别是ECMA规范给的定义,如果没有实战经验,你很难从定义去理解它.下面是作者从作用域链慢慢讲到 ...
- 如何订阅Linux相关的邮件列表
转:http://blog.163.com/sunshine_linting/blog/static/44893323201282114012845/ 1.google"linux kern ...