Java 7之传统I/O - ByteArrayInputStream和ByteArrayOutputStream

先来看ByteArrayOutputStream类中write()方法:

 // Writes the specified byte to this byte array output stream.
    public synchronized void write(int b) {
        ensureCapacity(count + 1);
        buf[count] = (byte) b;
        count += 1;
    }
    /**
     * Writes len bytes from the specified byte array
     * starting at offset off to this byte array output stream.
     */
    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;
    }
这个类也是通过向数组中定入值来进行数值传递的,而字节数组的大小可以在创建ByteArrayOutputStream时通过构造函数指定,默认的大小为32.如果在调用write()方法时,都会确保字节数组的容量。如果过小,会自动进行扩容操作。这样就可以把需要的数据写到字节数组中去了。还可以通过调用writeTo()方法可以写入到其他输出流中,源代码如下:

 /**
     * Writes the complete contents of this byte array output stream to
     * the specified output stream argument, as if by calling the output
     * stream's write method using out.write(buf, 0, count).
     */
    public synchronized void writeTo(OutputStream out) throws IOException {
        out.write(buf, 0, count);
    }

继续来看ByteArrayInputStream类,这个类可以从字节数组中读出数据,具体的源代码如下:

 public synchronized int read() {
        return (pos < count) ? (buf[pos++] & 0xff) : -1;
    }

    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;
    }
同时也提供了其他的一些方法,如可以跳读字节的skip()方法、查看剩余有效字节的avaible()方法等等,有兴趣的可以自己去看。下面来举一个具体应用的例子,如下:

byte[] bytes = { 0,2, 3, 4, 5 };
		try (ByteArrayOutputStream out = new ByteArrayOutputStream();
			 ByteArrayInputStream in = new ByteArrayInputStream(bytes);){
			out.write(bytes);
			System.out.println(out.size());//5
			System.out.println(in.read());//解
			in.skip(1);//2
			in.mark(4);
			System.out.println(in.read());//3
			in.reset();// 从索引为2的地方重新开始读
			System.out.println(in.read());//3 
			System.out.println(in.read());
			
		} catch (IOException e) {
			e.printStackTrace();
		}

4、StringBufferInputStream

这个类现在已经不提倡使用了,个人觉得是因为编码的原因吧。查看这个类后的源代码,如下:

 public synchronized int read() {
        return (pos < count) ? (buffer.charAt(pos++) & 0xFF) : -1;
    }

     public synchronized int read(byte b[], int off, int len) {
        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();
        }
        if (pos >= count) {
            return -1;
        }
        if (pos + len > count) {
            len = count - pos;
        }
        if (len <= 0) {
            return 0;
        }
        String  s = buffer;
        int cnt = len;
        while (--cnt >= 0) {
            b[off++] = (byte)s.charAt(pos++);
        }

        return len;
    }

发现,其实这个类是将字符串中的字符转换为字节进行读取的,如果这个字符串的字符全部为ISO-8859-1编码所能表示的,那肯定能正常读取。但是通常Java都是Unicode编码,两个字符,所以如果其中出现了Unicode字符的时候,例如中文,读取就会不准确。如下举例:

String str = "马智AB";
		StringBufferInputStream st = new StringBufferInputStream(str);
		byte[] j = new byte[16];
		st.read(j);
		System.out.println(new String(j)); //lzAB
原因可能大家也知道了,两个read()方法在获取到这个字符串的字符(s.charAt())后,强制转换为byte或与0xff相与,这样的结果只能导致取到低8位的编码,而对于两个字节编码的汉字来说,肯定会产生错误。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章