Skip to content

Commit

Permalink
read more about writer
Browse files Browse the repository at this point in the history
  • Loading branch information
minixalpha committed Jun 30, 2014
1 parent 7e0b20d commit b2e8eb9
Show file tree
Hide file tree
Showing 5 changed files with 383 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# OpenJDK 源码阅读之 BufferedWriter

标签(空格分隔): 源代码阅读 Java 封神之路

---

## 概要

* 类继承关系

```java
java.lang.Object
java.io.Writer
java.io.BufferedWriter
```

* 定义

```java
public class BufferedWriter
extends Writer
```

* 要点

增加了缓冲功能,要写入的数据,不会立即写入,而会先放在缓冲区,待缓冲区满,或者调用 `flush` 时,一次写入,以提升效率。另外,还添加了 `newLine` 函数。


## 实现


* 构造器

```java
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize);
}
```

需要一个底层的流,用于写入数据,还需要指定缓冲区大小,默认是 `8192`


```java
public BufferedWriter(Writer out, int sz) {
super(out);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.out = out;
cb = new char[sz];
nChars = sz;
nextChar = 0;

lineSeparator = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}
```

初始化时,会保存好底层流,并生成缓冲区,指定好当前写入数据的位置,另外,还需要获取行分割符号,因为不同系统的行分割符号是不一样的。


* write

```java
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
}
```

需要写入的数据,放在缓冲区 `cb` 中,如果缓冲区满,就调用 `flushBuffer` 写入。

* flushBuffer

```java
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
```

刷新缓冲区时,会调用底层流的 `write` 函数,具体怎么写入,就要看底层流的 `write` 是如何实现的了。


Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# OpenJDK 源码阅读之 CharArrayWrite

标签(空格分隔): 源代码阅读 Java 封神之路

---

## 概要

* 类继承关系

```java
java.lang.Object
java.io.Writer
java.io.CharArrayWriter
```

* 定义

```java
public class CharArrayWriter
extends Writer
```

* 要点

将数据写入字符数组中,可以通过 `toCharArray`,`toString` 得到这个数组,数组大小会自动扩充。


## 实现

* 数组

```java
protected char buf[];
```

字符会被写入到这样一个数组内。


* 构造器

默认情况下,这个数组大小为 32


```java
public CharArrayWriter() {
this(32);
}

public CharArrayWriter(int initialSize) {
if (initialSize < 0) {
throw new IllegalArgumentException("Negative initial size: "
+ initialSize);
}
buf = new char[initialSize];
}
```

* write

```java
public void write(int c) {
synchronized (lock) {
int newcount = count + 1;
if (newcount > buf.length) {
buf = Arrays.copyOf(buf, Math.max(buf.length << 1, newcount));
}
buf[count] = (char)c;
count = newcount;
}
}
```

`write` 时,会将数据写入 `buf` 数组里,如果数组满了,会调用 `Arrays.copyOf` 扩充,并复制数据,生成新的数组。 扩充策略是现有大小翻倍。

* toCharArray

```java
public char toCharArray()[] {
synchronized (lock) {
return Arrays.copyOf(buf, count);
}
}
```

`toCharArray` 会把内部数组复制一份,而不是直接返回内部的数组。


Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# OpenJDK 源码阅读之 OutputStreamWrite

标签(空格分隔): 源代码阅读 Java 封神之路

---

## 概要

* 类继承关系

```java
java.lang.Object
java.io.Writer
java.io.OutputStreamWriter
```

* 定义

```java
public class OutputStreamWriter
extends Writer
```

* 要点

这个类根据 charset 将字节流转化成字符流。


## 实现

* 编码器

```java
private final StreamEncoder se;
```

这是此类的核心,所有操作,都会用这个编码器完成。

* 构造器

```java
public OutputStreamWriter(OutputStream out, String charsetName)
throws UnsupportedEncodingException
{
super(out);
if (charsetName == null)
throw new NullPointerException("charsetName");
se = StreamEncoder.forOutputStreamWriter(out, this, charsetName);
}
```

构造函数可以指定 `charset` 的名字,同一个字节流,如果编码方式不同,转化出的字符就不同,所以,需要指定 `charset`,然后,通过 `StreamEncoder.forOutputStreamWriter` 得到编码器。如果没有指定:

```java
public OutputStreamWriter(OutputStream out) {
super(out);
try {
se = StreamEncoder.forOutputStreamWriter(out, this, (String)null);
} catch (UnsupportedEncodingException e) {
throw new Error(e);
}
}
```

`charsetName` 的参数位置上,会传入空,`forOutputStreamWriter` 会寻找系统的相应设置,如果找不到,会被设置为 `UTF-8`

* write

```java
public void write(int c) throws IOException {
se.write(c);
}
```

调用的是编码器的 `write`,它会将 `c` 按照 charset 编码,然后写入。`write` 背后最终的编码函数是一个 `native` 函数。

其它函数,如 `flush, close` 都是调用 `se` 的相应函数实现的。
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# OpenJDK 源码阅读之 StringBuffer

标签(空格分隔): 源代码阅读 Java 封神之路

---

## 概要

* 类继承关系

```java
java.lang.Object
java.io.Writer
java.io.StringWriter
```

* 定义

```java
public class StringWriter
extends Writer
```

* 要点

将数据写入一个 string 缓冲区内,当需要时,会转化成 string,听起来很像 CharArrayWriter 啊,不知道有什么不同。


## 实现

* 内部缓冲

```java
private StringBuffer buf;
```

内部是使用 `StringBuffer` 保存写入的数据的。


* 构造器

```java
public StringWriter() {
buf = new StringBuffer();
lock = buf;
}
```

初始化时,会生成 `StringBuffer` 对象,并设置锁,由于多个线程共同操作此对象时,会共享 buf ,所以锁就在 buf 上。


* write

```java
public void write(int c) {
buf.append((char) c);
}
```

`write` 就是调用了 `StringBuffer``append` 函数,不过从这里看,也没有使用锁啊。。不过,`append` 函数本身就是带有 `synchronized` 关键字的。

另外,这个类还提供了写入 string 功能。

```java
public void write(String str) {
buf.append(str);
}
```

似乎是在类中,为 `StringBuffer` 的一些方法提供了相应的接口。
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# OpenJDK 源码阅读之 Writer

标签(空格分隔): 源代码阅读 Java 封神之路

---

## 概要

* 类继承关系

```java
java.lang.Object
java.io.Writer
```

* 定义

```java
public abstract class Writer
extends Object
implements Appendable, Closeable, Flushable
```

* 要点

写入字符流的抽象类,其子类必需实现 `write(char[], int, int), flush(), and close()`,另外,也会添加或者覆盖其它方法,以提升效率或增加功能。


## 实现

* write

```java
public void write(int c) throws IOException {
synchronized (lock) {
if (writeBuffer == null){
writeBuffer = new char[writeBufferSize];
}
writeBuffer[0] = (char) c;
write(writeBuffer, 0, 1);
}
}
```

注意,会用一个 `writeBuffer` 保存要写入的数据,然后调用 `write(char[], int, int)` 写入数据,这个函数是个抽象函数,具体实现由子类完成。

另外两个子类需要实现的函数是:

```java
abstract public void flush() throws IOException;
abstract public void close() throws IOException;
```




0 comments on commit b2e8eb9

Please sign in to comment.