diff --git a/README.md b/README.md
index 8544803..678d34c 100644
--- a/README.md
+++ b/README.md
@@ -81,19 +81,19 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过
### 常见问题
-* [进程的当前工作目录是什么? 有什么作用?](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#q-cwd)
-* [child_process.fork 与 POSIX 的 fork 有什么区别?](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#q-fork)
-* [父进程或子进程的死亡是否会影响对方? 什么是僵死进程?](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#q-child)
-* [什么是守护进程? 如何实现守护进程?](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#守护进程)
+* 进程的当前工作目录是什么? 有什么作用? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#q-cwd)
+* child_process.fork 与 POSIX 的 fork 有什么区别? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#q-fork)
+* 父进程或子进程的死亡是否会影响对方? 什么是僵死进程? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#q-child)
+* 什么是守护进程? 如何实现守护进程? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md#守护进程)
[阅读更多](https://github.com/ElemeFE/node-interview/blob/master/sections/process.md)
-## IO
+## [IO](https://github.com/ElemeFE/node-interview/blob/master/sections/io.md)
-* `[Doc]` Stream (流)
* `[Doc]` Buffer
* `[Doc]` String Decoder (字符串解码)
+* `[Doc]` Stream (流)
* `[Doc]` Console (控制台)
* `[Doc]` File System (文件系统)
* `[Doc]` Readline
@@ -101,12 +101,14 @@ Hi, 欢迎来到 ElemeFE, 如标题所示本教程的目的是教你如何通过
### 常见问题
-* Stream 的 pipe 是如何使用? 在 pipe 的过程中数据是引用传递还是拷贝传递?
-* 什么是文件句柄? 输入流/输出流/错误流是什么?
-* console.log 是同步还是异步? 如何实现一个 console.log?
+* Buffer 一般用于处理什么数据? 其长度能否动态变化?
+* Stream 的 highWaterMark 与 drain 事件是什么? 二者之间的关系是? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/io.md#缓冲区)
+* Stream 的 pipe 的作用是? 在 pipe 的过程中数据是引用传递还是拷贝传递? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/io.md#pipe)
+* 什么是文件描述符? 输入流/输出流/错误流是什么?
+* console.log 是同步还是异步? 如何实现一个 console.log? [more](https://github.com/ElemeFE/node-interview/blob/master/sections/io.md#console)
* Readline 是如何实现的? 如何实现一个同步的 Readline?
-`更多整理中`
+[阅读更多](https://github.com/ElemeFE/node-interview/blob/master/sections/io.md)
## Network
diff --git a/sections/io.md b/sections/io.md
new file mode 100644
index 0000000..c0c6042
--- /dev/null
+++ b/sections/io.md
@@ -0,0 +1,258 @@
+# IO
+
+* `[Doc]` Stream (流)
+* `[Doc]` Buffer
+* `[Doc]` String Decoder (字符串解码)
+* `[Doc]` Console (控制台)
+* `[Doc]` File System (文件系统)
+* `[Doc]` Readline
+* `[Doc]` REPL
+
+# 简述
+
+Node.js 是以 IO 密集型业务著称. 那么问题来了, 你真的了解什么叫 IO, 什么又叫 IO 密集型吗?
+
+## Buffer
+
+Buffer 是 Node.js 中用于处理二进制数据的类, 其中与 IO 相关的操作 (网络/文件等) 均基于 Buffer. Buffer 类的实例非常类似整数数组, 但其大小是固定不变的, 并且其内存在 V8 堆栈外分配原始内存空间. Buffer 类的实例创建之后, 其所占用的内存大小就不能再进行调整.
+
+在 Node.js v6.x 之后 `new Buffer()` 接口开始被废弃, 理由是参数类型不同会返回不同类型的 Buffer 对象, 所以当开发者没有正确校验参数或没有正确初始化 Buffer 对象的内容时, 以及不了解的情况下初始化 就会在不经意间向代码中引入安全性和可靠性问题.
+
+接口|用途
+---|---
+Buffer.from()|根据已有数据生成一个 Buffer 对象
+Buffer.alloc()|创建一个初始化后的 Buffer 对象
+Buffer.allocUnsafe()|创建一个未初始化的 Buffer 对象
+
+### TypedArray
+
+Node.js 的 Buffer 在 ES6 增加了 TypedArray 类型之后, 修改了原来的 Buffer 的实现, 选择基于 TypedArray 中 Uint8Array 来实现, 从而提升了一波性能.
+
+使用上, 你需要了解如下例子:
+
+```javascript
+const arr = new Uint16Array(2);
+arr[0] = 5000;
+arr[1] = 4000;
+
+const buf1 = Buffer.from(arr); // 拷贝了该 buffer
+const buf2 = Buffer.from(arr.buffer); // 与该数组共享了内存
+
+console.log(buf1);
+// 输出: , 拷贝的 buffer 只有两个元素
+console.log(buf2);
+// 输出:
+
+arr[1] = 6000;
+console.log(buf1);
+// 输出:
+console.log(buf2);
+// 输出:
+```
+
+## String Decoder
+
+字符串解码器 (String Decoder) 是一个用于将 Buffer 拿来 decode 到 string 的模块, 是作为 Buffer.toString 的一个补充, 它支持多字节 UTF-8 和 UTF-16 字符. 例如
+
+```javascript
+const StringDecoder = require('string_decoder').StringDecoder;
+const decoder = new StringDecoder('utf8');
+
+const cent = Buffer.from([0xC2, 0xA2]);
+console.log(decoder.write(cent)); // ¢
+
+const euro = Buffer.from([0xE2, 0x82, 0xAC]);
+console.log(decoder.write(euro)); // €
+```
+
+当然也可以断断续续的处理.
+
+```javascript
+const StringDecoder = require('string_decoder').StringDecoder;
+const decoder = new StringDecoder('utf8');
+
+decoder.write(Buffer.from([0xE2]));
+decoder.write(Buffer.from([0x82]));
+console.log(decoder.end(Buffer.from([0xAC]))); // €
+```
+
+## Stream
+
+Node.js 内置的 `stream` 模块是多个核心模块的基础. 但是流 (stream) 是一种很早之前流行的编程方式. 可以用大家比较熟悉的 C语言来看这种流式操作:
+
+```c
+
+int copy(const char *src, const char *dest)
+{
+ FILE *fpSrc, *fpDest;
+ char buf[BUF_SIZE] = {0};
+ int lenSrc, lenDest;
+
+ // 打开要 src 的文件
+ if ((fpSrc = fopen(src, "r")) == NULL)
+ {
+ printf("文件 '%s' 无法打开\n", src);
+ return FAILURE;
+ }
+
+ // 打开 dest 的文件
+ if ((fpDest = fopen(dest, "w")) == NULL)
+ {
+ printf("文件 '%s' 无法打开\n", dest);
+ fclose(fpSrc);
+ return FAILURE;
+ }
+
+ // 从 src 中读取 BUF_SIZE 长的数据到 buf 中
+ while ((lenSrc = fread(buf, 1, BUF_SIZE, fpSrc)) > 0)
+ {
+ // 将 buf 中的数据写入 dest 中
+ if ((lenDest = fwrite(buf, 1, lenSrc, fpDest)) != lenSrc)
+ {
+ printf("写入文件 '%s' 失败\n", dest);
+ fclose(fpSrc);
+ fclose(fpDest);
+ return FAILURE;
+ }
+ // 写入成功后清空 buf
+ memset(buf, 0, BUF_SIZE);
+ }
+
+ // 关闭文件
+ fclose(fpSrc);
+ fclose(fpDest);
+ return SUCCESS;
+}
+```
+
+应用的场景很简单, 你要拷贝一个 20G 大的文件, 如果你一次性将 20G 的数据读入到内存, 你的内存条可能不够用, 或者严重影响性能. 但是你如果使用一个 1MB 大小的缓存 (buf) 每次读取 1Mb, 然后写入 1Mb, 那么不论这个文件多大都只会占用 1Mb 的内存.
+
+而在 Node.js 中, 原理与上述 C 代码类似, 不过在读写的实现上通过 libuv 与 EventEmitter 加上了异步的特性. 在 linux/unix 中你可以通过 `|` 来感受到流式操作.
+
+### Stream 的类型
+
+类|使用场景|重写方法
+--|------|-------
+[Readable](https://github.com/substack/stream-handbook#readable-streams)|只读|_read
+[Writable](https://github.com/substack/stream-handbook#writable-streams)|只写|_write
+[Duplex](https://github.com/substack/stream-handbook#duplex)|读写|_read, _write
+[Transform](https://github.com/substack/stream-handbook#transform)|操作被写入数据, 然后读出结果|_transform, _flush
+
+### 对象模式
+
+通过 Node API 创建的流, 只能够对字符串或者 buffer 对象进行操作. 但其实流的实现是可以基于其他的 Javascript 类型(除了 null, 它在流中有特殊的含义)的. 这样的流就处在 "对象模式" 中.
+在创建流对象的时候, 可以通过提供 objectMode 参数来生成对象模式的流. 试图将现有的流转换为对象模式是不安全的.
+
+### 缓冲区
+
+Node.js 中 stream 的缓冲区, 以开头的 C语言 拷贝文件的代码为模板讨论, (抛开异步的区别看) 则是从 src 中读出数据到 buf 中后, 并没有直接写入 dest 中, 而是先放在一个比较大的缓冲区中, 等待写入(消费) dest 中. 即, 在缓冲区的帮助下可以使读与写的过程分离.
+
+Readable 和 Writable 流都会将数据储存在内部的缓冲区中. 缓冲区可以分别通过 writable._writableState.getBuffer() 和 readable._readableState.buffer 来访问. 缓冲区的大小, 由构造 stream 时候的 highWaterMark 标志指定可容纳的 byte 大小, 对于 objectMode 的 stream, 该标志表示可以容纳的对象个数.
+
+#### 可读流
+
+当一个可读实例调用 stream.push() 方法的时候, 数据将会被推入缓冲区. 如果数据没有被消费, 即调用 stream.read() 方法读取的话, 那么数据会一直留在缓冲队列中. 当缓冲区中的数据到达 highWaterMark 指定的阈值, 可读流将停止从底层汲取数据, 直到当前缓冲的报备成功消耗为止.
+
+#### 可写流
+
+在一个在可写实例上不停地调用 writable.write(chunk) 的时候数据会被写入可写流的缓冲区. 如果当前缓冲区的缓冲的数据量低于 highWaterMark 设定的值, 调用 writable.write() 方法会返回 true (表示数据已经写入缓冲区), 否则当缓冲的数据量达到了阈值, 数据无法写入缓冲区 write 方法会返回 false, 直到 drain 时间触发之后才能继续调用 write 写入.
+
+```javascript
+// Write the data to the supplied writable stream one million times.
+// Be attentive to back-pressure.
+function writeOneMillionTimes(writer, data, encoding, callback) {
+ let i = 1000000;
+ write();
+ function write() {
+ var ok = true;
+ do {
+ i--;
+ if (i === 0) {
+ // last time!
+ writer.write(data, encoding, callback);
+ } else {
+ // see if we should continue, or wait
+ // don't pass the callback, because we're not done yet.
+ ok = writer.write(data, encoding);
+ }
+ } while (i > 0 && ok);
+ if (i > 0) {
+ // had to stop early!
+ // write some more once it drains
+ writer.once('drain', write);
+ }
+ }
+}
+```
+
+#### Duplex 与 Transform
+
+Duplex 流和 Transform 流都是同时可读写的, 他们会在内部维持两个缓冲区, 分别对应读取和写入, 这样就可以允许两边同时独立操作, 维持高效的数据流. 比如说 net.Socket 是一个 Duplex 流, Readable 端允许从 socket 获取、消耗数据, Writable 端允许向 socket 写入数据. 数据写入的速度很有可能与消耗的速度有差距, 所以两端可以独立操作和缓冲是很重要的.
+
+### pipe
+
+stream 的 .pipe(), 将一个可写流附到可读流上, 同时将可写流切换到流模式, 并把所有数据推给可写流. 在 pipe 传递数据的过程中, objectMode 是传递引用, 非 objectMode 则是拷贝一份数据传递下去.
+
+pipe 方法最主要的目的就是将数据的流动缓冲到一个可接受的水平, 不让不同速度的数据源之间的差异导致内存被占满. 关于 pipe 的实现请看 David Cai 的 [通过源码解析 Node.js 中导流(pipe)的实现](https://cnodejs.org/topic/56ba030271204e03637a3870)
+
+## Console
+
+[console.log 正常情况下是异步的, 除非你使用 `new Console(stdout[, stderr])` 指定了一个文件为目的地](https://nodejs.org/dist/latest-v6.x/docs/api/console.html#console_asynchronous_vs_synchronous_consoles). 不过一般情况下的实现都是如下 ([6.x 源代码](https://github.com/nodejs/node/blob/v6.x/lib/console.js#L42)):
+
+```javascript
+// As of v8 5.0.71.32, the combination of rest param, template string
+// and .apply(null, args) benchmarks consistently faster than using
+// the spread operator when calling util.format.
+Console.prototype.log = function(...args) {
+ this._stdout.write(`${util.format.apply(null, args)}\n`);
+};
+```
+
+自己实现一个 console.log 可以参考如下代码:
+
+```javascript
+let print = (str) => process.stdout.write(str + '\n');
+
+print('hello world');
+```
+
+注意: 该代码并没有处理多参数, 也没有处理占位符 (即 util.format 的功能).
+
+### console.log.bind(console) 问题
+
+[console.js 源代码](https://github.com/nodejs/node/blob/v6.x/lib/console.js#L34)
+
+```javascript
+function Console(stdout, stderr) {
+ // ... init ...
+
+ // bind the prototype functions to this Console instance
+ var keys = Object.keys(Console.prototype);
+ for (var v = 0; v < keys.length; v++) {
+ var k = keys[v];
+ this[k] = this[k].bind(this);
+ }
+}
+```
+
+## File
+
+“一切皆是文件”是 Unix/Linux 的基本哲学之一, 不仅普通的文件、目录、字符设备、块设备、套接字等在 Unix/Linux 中都是以文件被对待, 也就是说这些资源的操作对象均为 fd (文件描述符), 都可以通过同一套 system call 来读写. 在 linux 中你可以通过 ulimit 来管理 fd 资源.
+
+Node.js 封装了标准 POSIX 文件 I/O 操作的集合. 通过 require('fs') 可以加载该模块. 该模块中的所有方法都有异步执行和同步执行两个版本. 你可以通过 fs.open 获得一个文件的文件描述符.
+
+### stdio
+
+标准的 IO 流, 即输入流 (stdin), 输出流 (stdout), 错误流 (stderr).
+
+
+
+整理中
+
+## Readline
+
+整理中
+
+## REPL
+
+整理中