|
字节输入流的学习告一段落了,接下来的一段时间学习字符输入流。本文学习字符输入流的抽象类Reader与和字符输出流的抽象类Writer。 ReaderReader是字符输入流的抽象类。子类必须实现的方法只有read(char[], int, int) 和close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。 下面学习下Reader.java的源码。 public abstract class Reader implements Readable, Closeable { protected Object lock;//用于同步针对此流的操作的对象。 /** * 构造函数之一 * 创建一个新的字符流Reader,其重要部分将同步其自身。 */ protected Reader() { this.lock = this; } /** * 构造函数之一 * 创建一个新的字符流reader,其重要部分将同步给定的对象lock */ protected Reader(Object lock) { if (lock == null) { throw new NullPointerException(); } this.lock = lock; } /** * 试图将字符读入指定的字符缓冲区。 * 缓冲区可照原样用作字符的存储库:所做的唯一改变是put操作的结果。不对缓冲区执行翻转或重绕操作。 * 将输入流管道中的target.length个字节读取到指定的缓存字符数组target中、返回实际存放到target中的字符数。 */ public int read(java.nio.CharBuffer target) throws IOException { //获取此缓冲区中的剩余元素数 int len = target.remaining(); char[] cbuf = new char[len]; //试图将输入流中的len个字符读入cbuf,返回实际读取的字节数n int n = read(cbuf, 0, len); //如果实际读到字符的个数大于0 if (n > 0) //将实际读取到的n个字符存入缓冲区 target.put(cbuf, 0, n); //返回实际读取的字符数 return n; } /** * 从输入流中读取单个字符。 */ public int read() throws IOException { char cb[] = new char[1]; if (read(cb, 0, 1) == -1) return -1; else return cb[0]; } /** * 从输入流中读取一定数量的字符并把它们保存到缓冲数组b中。返回读取的字节数。 */ public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); } /** * 从输入流中,读取最多len个字节到字符数组中。 * * @param cbuf 存储读入数据的字节数组。 * @param off 起始偏移量 * @param len 读取的最大字节数。 * @return 读入字节数组的总字节数,如果由于已到达流末尾而不再有数据,则返回-1。 */ abstract public int read(char cbuf[], int off, int len) throws IOException; /** 存放被跳过字节的缓冲区的最大值 */ private static final int maxSkipBufferSize = 8192; /** 存放被跳过字节的缓冲区 */ private char skipBuffer[] = null; /** * 跳过字符 * * @param n 要跳过的字符数 * @return 实际跳过的字符数 * */ public long skip(long n) throws IOException { //如果n为负数,抛出异常 if (n < 0L) throw new IllegalArgumentException("skip value is negative"); //不允许n大于maxSkipBufferSize int nn = (int) Math.min(n, maxSkipBufferSize); synchronized (lock) { //如果现有缓冲区为null或者大小小于nn,就新建一个大小为nn的缓冲区 if ((skipBuffer == null) || (skipBuffer.length < nn)) skipBuffer = new char[nn]; long r = n; //循环跳过输入流中字符,一次尝试跳过nn个字符,直到到达输入流末尾或者n个字符被全部跳过 while (r > 0) { int nc = read(skipBuffer, 0, (int)Math.min(r, nn)); if (nc == -1) break; r -= nc; } //返回实际跳过的字符数 return n - r; } } /** * 检测此流是否可读 * 默认返回false */ public boolean ready() throws IOException { return false; } /** * 判断此流是否支持mark()操作。默认实现始终返回 false。 */ public boolean markSupported() { return false; } /** * 标记流中的当前位置。与reset()配合使用。reset()的后续调用将尝试将该流重新定位到此点。 * 该方法需要子类重写 */ public void mark(int readAheadLimit) throws IOException { throw new IOException("mark() not supported"); } /** * 将流的读取位置重置到最后一次调用mark方法时的位置 * 该方法需要子类重写 */ public void reset() throws IOException { throw new IOException("reset() not supported"); } /** * 关闭该流并释放与之关联的所有资源。 */ abstract public void close() throws IOException;}- 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
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
WriterWriter是字符输出流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。 下面学习下Writer的源码。 public abstract class Writer implements Appendable, Closeable, Flushable { /** * 字符缓存数组。 * 用于临时存放要写入字符输出流中的字符 */ private char[] writeBuffer; /** * 字符缓存数组的默认大小。 */ private static final int WRITE_BUFFER_SIZE = 1024; /** * 用于同步针对此流的操作的对象。 */ protected Object lock; /** * 构造方法 * 创建一个新的字符流writer,其关键部分将同步其自身。 */ protected Writer() { this.lock = this; } /** * 构造方法 * 建一个新的字符流writer,其关键部分将同步给定的对象。 */ protected Writer(Object lock) { if (lock == null) { throw new NullPointerException(); } this.lock = lock; } /** * 写入单个字符。 * 要写入的字符包含在给定整数值的16个低位中,16高位被忽略。 */ public void write(int c) throws IOException { synchronized (lock) { if (writeBuffer == null){ writeBuffer = new char[WRITE_BUFFER_SIZE]; } //char为16位。所以要写入的字符包含在给定整数值的16个低位中,16高位被忽略。 writeBuffer[0] = (char) c; write(writeBuffer, 0, 1); } } /** * 将一个字符数组写入到writerBuffer中 */ public void write(char cbuf[]) throws IOException { write(cbuf, 0, cbuf.length); } /** * 试图将字符数组中从off开始的len个字符写入输出流中。 * 尽量写入len个字符,但写入的字节数可能少于len个,也可能为零。 */ abstract public void write(char cbuf[], int off, int len) throws IOException; /** * 写入字符串 */ public void write(String str) throws IOException { write(str, 0, str.length()); } /** * 试图将字符串中从off开始的len个字符写入输出流中。 * 尽量写入len个字符,但写入的字节数可能少于len个,也可能为零。 * * @param 试图写入的字符串 * @param off 偏移量 * @param 试图写入的长度 * @throws IndexOutOfBoundsException 如果off或len为负,或者off+len 为负或大于给定字符串的长度 */ public void write(String str, int off, int len) throws IOException { synchronized (lock) { char cbuf[]; if (len <= WRITE_BUFFER_SIZE) { if (writeBuffer == null) { writeBuffer = new char[WRITE_BUFFER_SIZE]; } cbuf = writeBuffer; } else { // Don't permanently allocate very large buffers. cbuf = new char[len]; } //将字符串中从off开始到off+len的字符复制到cbuf中 str.getChars(off, (off + len), cbuf, 0); write(cbuf, 0, len); } } /** * 添加字符序列 */ public Writer append(CharSequence csq) throws IOException { if (csq == null) write("null"); else write(csq.toString()); return this; } /** * 添加字符序列的一部分 */ public Writer append(CharSequence csq, int start, int end) throws IOException { CharSequence cs = (csq == null ? "null" : csq); write(cs.subSequence(start, end).toString()); return this; } /** * 添加指定字符 */ public Writer append(char c) throws IOException { write(c); return this; } /** * 刷新该流的缓冲。 */ abstract public void flush() throws IOException; /** * 关闭此流,但要先刷新它。 */ abstract public void close() throws IOException;}- 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
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
总结- Reader是字符输入流的抽象类。子类必须实现的方法只有read(char[], int, int) 和close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。如重写read方法提供更高的效率;重写mark/set方法提供标记功能。
- Writer是字符输出流的抽象类。子类必须实现的方法仅有 write(char[], int, int)、flush() 和 close()。但是,多数子类将重写此处定义的一些方法,以提供更高的效率和/或其他功能。
Reader与InputStream区别- 操作对象的不同。字节流操作字节、字符操作字符。
- 实现的接口不同。Reader比InputStream多实现了一个Readable接口,用于提供一个可以将字符写入到指定缓存数组的方法。
- close方法不同。Reader的close方法是抽象的、子类必须重写。 InputStream的close方法则不是抽象的。
Writer与OutputStream区别- 操作对象的不同。字节流操作字节、字符操作字符。
- 实现的接口不同。Writer相比与OutputStream多实现了一个Appendable接口、用于提供几个向此流中追加字符的方法。
- close、flush方法不同。Writer的close、flush方法都是抽象的,而OutputStream则不是。
关于Reader与Writer就讲到这里,想了解更多内容请参考 版权声明
|