Fork me on GitHub

【IO】IO字符流

IO字符流

1. 框架

2. CharArrayReader/CharArrayWriter

  • CharArrayReader 是字符数组输入流。它和ByteArrayInputStream类似,操作的数据是以字符为单位
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CharArrayReader extends Reader {
// 字符数组缓冲
protected char buf[];
// 下一个被获取的字符的位置
protected int pos;
// 被标记的位置
protected int markedPos = 0;
// 字符缓冲的长度
protected int count;
// 构造函数
public CharArrayReader(char buf[]) {
this.buf = buf;
this.pos = 0;
this.count = buf.length;
}
}
  • CharArrayReader 是字符数组输出流,用于写入数据符。操作的数据是以字符为单位
  • CharArrayReader 默认数组缓冲区大小为32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 写入字符数组c到CharArrayWriter中。off是“字符数组b中的起始写入位置”,len是写入的长度
public void write(char c[], int off, int len) {
if ((off < 0) || (off > c.length) || (len < 0) ||
((off + len) > c.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return;
}
synchronized (lock) {
int newcount = count + len;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));//扩容操作
}
System.arraycopy(c, off, buf, count, len);
count = newcount;
}
}

3. PipedReader/PipedWriter

  • PipedWriter 是字符管道输出流,它继承于Writer。 PipedReader 是字符管道输入流,它继承于Writer。
  • 同“PipedInputStream和PipedOutputStream”一样,可以通过管道进行线程间的通讯
  • PipedWriter 和PipedReader 需要成对使用,使用connect连接
  • PipedWriter 中write方法,实际调用的PipedReader 的receive方法,将数据写入管道输入流的缓冲字符数组,通过in(下一个写入字符位置)和out(下一个读取字符位置)判断数据是否读完,线程等待状态

4. InputStreamReader/OutputStreamWriter

  • InputStreamReader和OutputStreamWriter 是字节流通向字符流的桥梁:它使用指定的 charset 读写字节并将其解码为字符。
  • InputStreamReader 的作用是将“字节输入流”转换成“字符输入流”。它继承于Reader。
  • OutputStreamWriter 的作用是将“字节输出流”转换成“字符输出流”。它继承于Writer。

5. FileReader/FileWriter

  • FileReader 是用于读取字符流的类,它继承于InputStreamReader。要读取原始字节流,请考虑使用 FileInputStream。
  • FileWriter 是用于写入字符流的类,它继承于OutputStreamWriter。要写入原始字节流,请考虑使用 FileOutputStream。
  • FileReader是基于InputStreamReader实现的,构造函数传入FileInputStream
  • FileWriter是基于OutputStreamWriter实现的,构造函数传入FileOutputStream

6. BufferedReader/BufferedWriter

6.1 BufferedReader

  • BufferedReader 是缓冲字符输入流。它继承于Reader。
  • BufferedReader 的作用是为其他字符输入流添加一些缓冲功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
//从BufferedReader中读取一个字符,该字符以int的方式返回
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
if (nextChar >= nChars) {// 若“缓冲区的数据已经被读完”,
fill();
if (nextChar >= nChars)
return -1;
}
if (skipLF) {// 若要“忽略换行符”,
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
return cb[nextChar++];
}
}
}

// 填充缓冲区函数。有以下两种情况被调用:
// (01) 缓冲区没有数据时,通过fill()可以向缓冲区填充数据。
// (02) 缓冲区数据被读完,需更新时,通过fill()可以更新缓冲区的数据。
private void fill() throws IOException {
// dst表示“cb中填充数据的起始位置”。
int dst;
if (markedChar <= UNMARKED) {// 没有标记的情况
dst = 0;
} else {
// delta表示“当前标记的长度”,它等于“下一个被读取字符的位置”减去“标记的位置”的差值;
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
// 若“当前标记的长度”超过了“标记上限(readAheadLimit)”,
// 则丢弃标记!
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
// 若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”,
// 并且“标记上限(readAheadLimit)”小于/等于“缓冲的长度”;
// 则先将“下一个要被读取的位置,距离我们标记的置符的距离”间的字符保存到cb中。
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
// 若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”,
// 并且“标记上限(readAheadLimit)”大于“缓冲的长度”;
// 则重新设置缓冲区大小,并将“下一个要被读取的位置,距离我们标记的置符的距离”间的字符保存到cb中。
char ncb[] = new char[readAheadLimit]; //当我们不停的更新缓冲区的时候,被标记的位置会被不停的放大。而内存的容量是有效的,我们不可能不限制长度的存储标记。所以用readAheadLimit来限制标记长度!
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
// 更新nextChar和nChars
nextChar = nChars = delta;
}
}

int n;
do {
// 从“in”中读取数据,并存储到字符数组cb中;
// 从cb的dst位置开始存储,读取的字符个数是cb.length - dst
// n是实际读取的字符个数;若n==0(即一个也没读到),则继续读取!
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);

// 如果从“in”中读到了数据,则设置nChars(cb中字符的数目)=dst+n,
// 并且nextChar(下一个被读取的字符的位置)=dst。
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}

6.2 BufferedWriter

  • BufferedWriter 是缓冲字符输出流。它继承于Writer。
  • BufferedWriter 的作用是为其他字符输出流添加一些缓冲功能
  • BufferedWriter通过字符数组来缓冲数据,当缓冲区满或者用户调用flush()函数时,它就会将缓冲区的数据写入到输出流中。

7. PrintWriter

  • PrintWriter 是字符类型的打印输出流,它继承于Writer。
  • PrintStream 用于向文本输出流打印对象的格式化表示形式。它实现在 PrintStream 中的所有 print 方法。它不包含用于写入原始字节的方法,对于这些字节,程序应该使用未编码的字节流进行写入。

8. 参考

http://www.cnblogs.com/skywang12345/p/io_01.html