Java IO 系列源码分析——ByteArrayInputStream和ByteArrayOutputStream
来源:互联网 发布:2017最新一手数据 编辑:程序博客网 时间:2024/05/17 21:44
ByteArrayInputStream
是字节数组输入流,继承于InputStream
,它内部包含一个缓冲区,该缓冲区存有从输入流中读取的字节。ByteArrayInputStream
内部还额外定义了一个计数器,用于记录read()
方法读取的下一个字节的位置 ByteArrayOutputStream
是字节数组输出流,继承于OutputStream
,它内部同样包含一个缓冲区,ByteArrayOutputStream
中的数据被写入该缓冲区,缓冲区的大小会随着写入数据的增加而增长。我们可以通过ByteArrayOutputStream
的toByteArray
和toString
方法来获取数据。
下面我们就分别对ByteArrayInputStream
和ByteArrayOutputStream
源码进行学习。
1. ByteArrayInputStream
源码分析(基于jdk1.8.0_66
)
Package java.io;public class ByteArrayInputStream extends InputStream { //内部缓冲区,保存字节输入流数据 protected byte buf[]; //计数器,标记下一次从内部缓冲区读取的位置 //范围:[0, count] protected int pos; //标记的索引,构造器初始化时默认为0 //调用mark方法可以标记到其他位置,调用reset方法 protected int mark = 0; //字节流的长度 protected int count; //构造一个缓冲区为buf的字节流 public ByteArrayInputStream(byte buf[]) { this.buf = buf; this.pos = 0; //设置下一次要被读取的索引为0 this.count = buf.length; //设置字节流长度为buf的长度 } //构造一个缓冲区为buf的字节流,并从offset开始读取数据,读取的长度最长不超过length public ByteArrayInputStream(byte buf[], int offset, int length) { this.buf = buf; this.pos = offset;//设置下一次要被读取的索引为offset this.count = Math.min(offset + length, buf.length); this.mark = offset;//设置标记的索引为offset } //实现了InputStream的read方法,读取下一个字节 public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1; } //将字节流中最多len个字节写入到数组b中,写入位置从下标off开始计算。 //返回实际写入的字节数 public synchronized int read(byte b[], int off, int len) { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } //字节流中无数据可读 if (pos >= count) { return -1; } int avail = count - pos; //字节流中可以被读取的字节数据长度 if (len > avail) { len = avail; } if (len <= 0) { return 0; } System.arraycopy(buf, pos, b, off, len); pos += len; return len; } //跳过字节流中最多n个字节,返回实际跳过的字节数 public synchronized long skip(long n) { long k = count - pos; //获取字节流中可以读取或者跳过的字节数目 if (n < k) { k = n < 0 ? 0 : n; } pos += k; return k; } //获取字节流中可以读取的字节数目 public synchronized int available() { return count - pos; } //测试该数据流是否支持标记 //ByteArrayInputStream支持标记 public boolean markSupported() { return true; } //标记当前位置,readAheadLimit暂时没有实际意义 public void mark(int readAheadLimit) { mark = pos; } //重置当前流的读取位置为最后一次调用mark方法标记的位置 public synchronized void reset() { pos = mark; } public void close() throws IOException { }}
ByteArrayOutputStream
源码分析
public class ByteArrayOutputStream extends OutputStream { //保存字节数组输出流数据的数组 protected byte buf[]; //数组中字节的数目,计数器 protected int count; //构造一个新的字节数组输出流,默认数组容量为32 public ByteArrayOutputStream() { this(32); } //构造一个新的字节数组输出流,默认数组容量为size public ByteArrayOutputStream(int size) { if (size < 0) { throw new IllegalArgumentException("Negative initial size: " + size); } buf = new byte[size]; } //确保数组容量,若数组容量小于minCapacity则扩展容量 private void ensureCapacity(int minCapacity) { // overflow-conscious code if (minCapacity - buf.length > 0) grow(minCapacity); } //数组允许分配的最大容量 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; //增加数组容量 private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = buf.length; int newCapacity = oldCapacity << 1;//新的数组容量为旧数组容量的2倍 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); buf = Arrays.copyOf(buf, newCapacity); } //若数组容量超过MAX_ARRAY_SIZE, 则根据minCapacity和Intege.MAX_VALUE大小来确定数组是否扩容 private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } /** * Writes the specified byte to this byte array output stream. * * @param b the byte to be written. */ //将指定字节b写入到该字节数组输出流,计数器+1 public synchronized void write(int b) { ensureCapacity(count + 1); buf[count] = (byte) b; count += 1; } //将数组b中从offset开始的len长度字节写入该字节数组输出流。计数器+len public synchronized void write(byte b[], int off, int len) { if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) - b.length > 0)) { throw new IndexOutOfBoundsException(); } ensureCapacity(count + len); System.arraycopy(b, off, buf, count, len); count += len; } //将该字节数组输出流中的字节数据全部写入到指定的输出流中 public synchronized void writeTo(OutputStream out) throws IOException { out.write(buf, 0, count); } //将计数器置零,以便向该字节数组输出流重新写入数据 public synchronized void reset() { count = 0; } //将该字节数组输出流数据写入到一个新的字节数组,并返回这个新的数组 public synchronized byte toByteArray()[] { return Arrays.copyOf(buf, count); } //返回字节数组输出流当前的计数器的数值 public synchronized int size() { return count; } public synchronized String toString() { return new String(buf, 0, count); } public synchronized String toString(String charsetName) throws UnsupportedEncodingException { return new String(buf, 0, count, charsetName); } @Deprecated public synchronized String toString(int hibyte) { return new String(buf, hibyte, 0, count); } public void close() throws IOException { }}
ByteArrayInputStream
示例 (测试基于 junit-4.12)
package test.io;import org.junit.Before;import org.junit.Test;import java.io.ByteArrayInputStream;import java.util.Arrays;public class ByteArrayInputStreamTest { private static final int LEN = 6; private static final byte[] byteArray = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; private ByteArrayInputStream bais; @Before public void beforeTest(){ //创建一个缓冲区为byteArray的字节数组输入流 bais = new ByteArrayInputStream(byteArray); } @Test public void testReadByte() { for (int i = 0; i < LEN; i++) { if (bais.available() > 0) { int tempByte = bais.read(); System.out.printf("%d, %s, %s\n", tempByte, Integer.toBinaryString(tempByte), Integer.toBinaryString('A' + i)); } } } @Test public void testReadBytes() { byte[] temp = new byte[LEN]; int len = bais.read(temp, 0, LEN); System.out.println("Total read " + len + " bytes"); System.out.println("The result is: " + Arrays.toString(temp)); System.out.println("The original array is: " + Arrays.toString(byteArray)); } @Test public void testSkip() { int temp1 = bais.read(); System.out.println("The byte is: " + temp1); Long skipNum = bais.skip(2); // 跳过2个字节 int temp2 = bais.read(); System.out.println("After skipping 2 bytes\nThe byte is: " + temp2); } @Test public void testAvailable() { int availableNum = bais.available(); System.out.println("Before reading, there are " + availableNum + " bytes available"); int temp = bais.read(); availableNum = bais.available(); System.out.printf("After reading %d, there are %d bytes available.\n", temp, availableNum); } @Test public void testMarkAndReset() { boolean isSupported = bais.markSupported(); System.out.println("mark() method is " + (isSupported ? "supported" : "not supported")); if (isSupported) { //标记当前位置,即byteArray[0] bais.mark(99999);//mark(readAheadLimit)中的readAheadLimit目前没有实际意义 int temp = bais.read(); //65 byteArray[0] temp = bais.read(); //66 byteArray[1] System.out.println("The next byte is " + bais.read());//should be 67 byteArray[2] //重置字节数组输入流的读取位置为最后一次mark标记的位置 bais.reset(); System.out.println("After resetting, the next byte is " + bais.read());//65 byteArray[0] } }}
ByteArrayOutputStream
实例 (测试基于 junit-4.12)
package test.io;import org.junit.Before;import org.junit.Test;import java.io.ByteArrayOutputStream;import java.io.IOException;public class ByteArrayOutputStreamTest { private static final int LEN = 6; private static final byte[] byteArray = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; private ByteArrayOutputStream baos; @Before public void beforeTest() { //创建一个字节数组输出流 baos = new ByteArrayOutputStream(); } @Test public void testWriteByte() { baos.write(byteArray[0]);//写入一个字节:A baos.write(byteArray[1]); baos.write(byteArray[2]); baos.write(byteArray[3]); baos.write(byteArray[4]); System.out.println("baos=" + baos); } @Test public void testWriteBytes() { baos.write(byteArray, 0, 5); //写入一组字节,从下标为0处开始,写入长度为5 } @Test public void testSize() { baos.write(byteArray[0]); baos.write(byteArray[1]); baos.write(byteArray[2]); System.out.println("The size of baos is: " + baos.size()); } @Test public void testWriteTo() { baos.write(byteArray[0]); baos.write(byteArray[1]); baos.write(byteArray[2]); //将baos写入到另外一个输出流中 ByteArrayOutputStream baos1 = new ByteArrayOutputStream(); try { baos.writeTo(baos1); System.out.println("baos1=" + baos1); } catch (IOException e) { e.printStackTrace(); } } @Test public void testToArray() { baos.write(byteArray[0]); baos.write(byteArray[1]); baos.write(byteArray[2]); byte[] temp = baos.toByteArray(); System.out.println("The contents is: "+ new String(temp)); }}
0 0
- Java IO 系列源码分析——ByteArrayInputStream和ByteArrayOutputStream
- JAVA IO系列----ByteArrayInputStream和ByteArrayOutputStream类
- Java IO ByteArrayInputStream和ByteArrayOutputStream
- JDK 1.7 java.io 源码学习之ByteArrayInputStream和ByteArrayOutputStream
- Java IO - ByteArrayInputStream&ByteArrayOutputStream
- Java IO操作——内存操作流{ByteArrayInputStream、ByteArrayOutputStream)
- 黑马程序员——Java IO—字节流—ByteArrayInputStream和ByteArrayOutputStream
- 17.Java IO: ByteArrayInputStream && ByteArrayOutputStream
- java IO笔记(ByteArrayInputStream/ByteArrayOutputStream)
- Java IO系列1 字节流之ByteArrayInputStream与ByteArrayOutputStream
- java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)
- java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)
- 黑马程序员——【Java】IO——操作字符数组的IO对象:ByteArrayInputStream & ByteArrayOutputStream
- java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)
- java io系列03之 ByteArrayOutputStream的简介,源码分析和示例(包括OutputStream)
- JAVA IO源码学习系列之ByteArrayInputStream
- Java IO--内存操作流ByteArrayInputStream/ByteArrayOutputStream
- java IO流分析:ByteArrayInputstream 和 BufferedInputStream
- SSH用通用dao更新出现的问题
- QT--------QLineEdit
- 【程序9】输出国际象棋棋盘
- Ubuntu 16.04 LTS 中通过grub修改root用户密码
- Oracle PL/SQL开发入门(第一弹:Oracle 11g数据库系统)
- Java IO 系列源码分析——ByteArrayInputStream和ByteArrayOutputStream
- 关于linux驱动管理笔记
- 一位资深程序员大牛给予Java初学者的学习建议
- thinking in java——0320学习笔记
- 性能优化三 使用索引的注意事项
- 用csdn来记录我的算法过程吧
- Linux下的find命令
- Softmax回归与Logistic回归
- 大数据工程师知识图谱