【给JDK IO源码加点注释】01 InputStream、OutputStream
InputStream
1 package java.io; 2 3 import java.util.Arrays; 4 import java.util.Objects; 5 抽象方法实现了closeable接口,可以在try with resource中使用。 6 public abstract class InputStream implements Closeable { 7 跳过缓存数组的最大值 8 private static final int MAX_SKIP_BUFFER_SIZE = 2048; 9 默认缓存数组大小 10 private static final int DEFAULT_BUFFER_SIZE = 8192; 11 12 /** 13 *读取流中下一个字节(0-255)。如果读完返回-1.此方法会导致阻塞。 14 * 15 * 抽象方法,子类必须提供此方法的实现. 16 * 17 * @return 流中下一个字节或者-1(当读取完时) 18 * 19 * @exception IOException if an I/O error occurs. 20 */ 21 public abstract int read() throws IOException; 22 23 /** 24 25 *试图读入多个字节,存入字节数组b,返回实际读入的字节数。 26 *如果传递的是一个空数组(注意数组长度可以为0,即空数组。比如 byte[] b = new byte[0]; 或者byte[] b = {};) 27 *那么什么也没读入,返回0. 28 *如果到达流尾部,没有字节可读,返回-1;如果上面两种情况都没有出现,并且没有I/O错误,则至少有1个字节被读入,存储到字节数组b中。 29 *实际读入的第一个字节存在b[0],往后一次存入数组,读入的字节数最多不能超过数组b的长度。 30 *如果读入的字节数小于b的长度,剩余的数组元素保持不 变。具体地,如果读入的字节数为k,则k个字节分别存在 b[0]到b[k-1],而b[k]到 *b[b.length-1]保持原来的数据。 31 * 32 * 此方法与read(b, 0, b.length)效果相同 33 * 34 * @param 存储读取字节的数组 35 * @return 0 如果传入的数组为空 36 * -1 此输入流没有字节可读取了 37 * int 实际读取的字节数 38 * @exception IOException 39 * @exception NullPointerException 传入数组b[]没有初始化 40 */ 41 public int read(byte b[]) throws IOException { 42 return read(b, 0, b.length); 43 } 44 45 /** 46 *读入的数据存储到b数组是从off开始。len是试图读入的字节数,返回的是实际读入的字节数。 47 *如果len=0,则什么也不读入,返回0;如果遇到流尾部,返回-1.否则至少读入一个字节。 48 * 49 * 第一个读取的字节存储到 b[off]中 , 下一个在b[off+1],直到b[off+len-1](数据量大于len时). 50 * 51 * 52 * @param b 存储读取字节的数组 53 * @param off 开始存放第一个读取数据的位置 54 * 55 * @param len 最大的字节数. 56 * @return 0 如果len为0 57 * -1 流中已经没有数据。 58 * int 实际读取的字节数(最大为len) 59 * @exception IOException 60 * @exception NullPointerException b[]为null 61 * @exception IndexOutOfBoundsException off,len为负数 或者 len大于b.length - off 62 */ 63 public int read(byte b[], int off, int len) throws IOException { 64 if (b == null) { 65 throw new NullPointerException(); 66 } else if (off < 0 || len < 0 || len > b.length - off) { 67 throw new IndexOutOfBoundsException(); 68 } else if (len == 0) { 69 return 0; 70 } 71 72 int c = read(); 73 if (c == -1) { 74 return -1; 75 } 76 b[off] = (byte)c; 77 78 int i = 1; 79 try { 80 for (; i < len ; i++) { 81 c = read(); 82 if (c == -1) { 83 break; 84 } 85 b[off + i] = (byte)c; 86 } 87 } catch (IOException ee) { 88 } 89 return i; 90 } 91 92 /** 93 * 缓存数组最大值 94 */ 95 private static final int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; 96 97 /** 98 * 读取流中剩下的全部字节 99 * 100 * 当流中没有数据时返回空的数组 101 * 102 * 103 * @return byte[] 流中全部字节 104 * @throws IOException if an I/O error occurs 105 * @throws OutOfMemoryError 当流中字节数大于Integer.MAX_VALUE - 8时,即数据大于2gb 106 * 107 * jdk9新增的方法 108 */ 109 public byte[] readAllBytes() throws IOException { 110 //创建一个缓存数组,用于存放读取的数据。 111 byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; 112 //读取的数据量 113 int capacity = buf.length; 114 //已经读取数据量 115 int nread = 0; 116 //一次读取的数量 117 int n; 118 //死循环读取数据相当于while(true) 119 for (;;) { 120 // 当流中还有数据,缓存数组未读满时,调用read方法读取数据到buf中 121 while ((n = read(buf, nread, capacity - nread)) > 0) 122 nread += n; 123 124 // 流中数据已读完,跳出死循环 125 if (n < 0) 126 break; 127 128 // 未跳出说明缓存数组已满需要扩大数组 129 if (capacity <= MAX_BUFFER_SIZE - capacity) { 130 capacity = capacity << 1; 131 } else { 132 if (capacity == MAX_BUFFER_SIZE) 133 throw new OutOfMemoryError("Required array size too large"); 134 capacity = MAX_BUFFER_SIZE; 135 } 136 buf = Arrays.copyOf(buf, capacity); 137 } 138 //返回 139 return (capacity == nread) ? buf : Arrays.copyOf(buf, nread); 140 } 141 142 /** 143 * 从 InputStream 中读取指定数量的字节到数组中与read(byte[] b,int off ,int len)相似 144 */ 145 public int readNBytes(byte[] b, int off, int len) throws IOException { 146 Objects.requireNonNull(b); 147 if (off < 0 || len < 0 || len > b.length - off) 148 throw new IndexOutOfBoundsException(); 149 int n = 0; 150 while (n < len) { 151 int count = read(b, off + n, len - n); 152 if (count < 0) 153 break; 154 n += count; 155 } 156 return n; 157 } 158 159 /** 160 * 试图跳过n个字节,返回实际跳过字节数的方法 161 * 例如流中只有6个字节,传入7只能跳过6,所以返回6. 162 * @param n 试图跳过的字节数. 163 * @return the 实际跳过的字节数. 164 * @throws IOException . 165 */ 166 public long skip(long n) throws IOException { 167 168 long remaining = n; 169 int nr; 170 171 if (n <= 0) { 172 return 0; 173 } 174 175 int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); 176 byte[] skipBuffer = new byte[size]; 177 while (remaining > 0) { 178 nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); 179 if (nr < 0) { 180 break; 181 } 182 remaining -= nr; 183 } 184 185 return n - remaining; 186 } 187 188 /** 189 * 返回流中可读取的字节数,具体由子类实现 190 */ 191 public int available() throws IOException { 192 return 0; 193 } 194 195 /** 196 * 关闭流 197 * @exception IOException if an I/O error occurs. 198 */ 199 public void close() throws IOException {} 200 201 /** 202 * 在当前位置定义一个标记,使用reset可以会到标记处,可以进行数据的重复读取。 203 * 204 * 205 * <p> Marking a closed stream should not have any effect on the stream. 206 * 207 * <p> The <code>mark</code> method of <code>InputStream</code> does 208 * nothing. 209 * 210 * @param readlimit 在标记后最大可读取数,超过此数字,标记过期,不允许reset。 211 * 212 * @see java.io.InputStream#reset() 213 */ 214 public synchronized void mark(int readlimit) {} 215 216 /** 217 * 用于重定位到最近的标记。如果在这之前mark方法从来没被调用,或者标记已经无效,在抛出IOException。 218 * 如果没有抛出这个异常,将当前位置重新定位到最近的标记位置。 219 * 220 * @exception 如果流未被标记。 221 * @see java.io.InputStream#mark(int) 222 * @see java.io.IOException 223 */ 224 public synchronized void reset() throws IOException { 225 throw new IOException("mark/reset not supported"); 226 } 227 228 /** 229 *返回流是否支持标记,默认未false。 230 */ 231 public boolean markSupported() { 232 return false; 233 } 234 235 /** 236 * 读取流中所有数据并写入到传入的输出流中 237 * @param 目标输出流 238 * @return 写入到输出流中的数据量 239 * @throws IOException 240 * @throws NullPointerException 当out为null时 241 * 242 * @since 9 243 */ 244 public long transferTo(OutputStream out) throws IOException { 245 Objects.requireNonNull(out, "out"); 246 long transferred = 0; 247 byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; 248 int read; 249 while ((read = this.read(buffer, 0, DEFAULT_BUFFER_SIZE)) >= 0) { 250 out.write(buffer, 0, read); 251 transferred += read; 252 } 253 return transferred; 254 } 255 }
OutputStream
package java.io; /** * 输出字节流抽象类 */ public abstract class OutputStream implements Closeable, Flushable { /** * 向流中写入特定的字节,截取低8位,忽略高24位。 * * @param b 待写入字节。 * @exception IOException */ public abstract void write(int b) throws IOException; /** * 向流中写入一个字节数组。 * * @param b 待写入字节数组。 * @exception IOException * @see java.io.OutputStream#write(byte[], int, int) */ public void write(byte b[]) throws IOException { write(b, 0, b.length); } /** * 将 b[]中off开始len个字节写入输出流中,即b[off]到b[off+len-1]。 * <p> * 如果b为null会抛出空指针异常 * 如果off,len为负,或者off+len比数组的长度大将抛出IndexOutOfBoundsException * * @param b 字节数组 * @param off 写入的其实位置 * @param len 写入的字节数 * @exception IOException */ public void write(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return; } for (int i = 0 ; i < len ; i++) { write(b[off + i]); } } public void flush() throws IOException { } /** * 关闭此输出流并释放资源。 * @exception IOException */ public void close() throws IOException { } }

浙公网安备 33010602011771号