JAVA常用类(IO篇)-DataOutputStream详解

文方便阅读和理解,本文翻译自源码,适合具有一定数据结构/算法基础且有志专研源码的朋友阅读,初学者请无视。错漏之处,多谢指正!

package java.io;
/**
 * DataOutputStream 可以实现java对象到流的便捷写入. 一个应用可以随后把流读出来 
 */
public
class DataOutputStream extends FilterOutputStream implements DataOutput {
    /**
     * 目前已经写入的byte数目
     * 如果counter值溢出了,它将被赋值为Integer.MAX_VALUE
     */
    protected int written;

    /**
     * bytearr 需要被writeUTF初始化
     */
    private byte[] bytearr = null;

    /**
     *创建一个新的data output stream用来向底层特定的output stream写数据,
     *计数器counter被设置为0
     *
     * @param   out   底层output strean,被保存起来以便后面用到
     * @see     java.io.FilterOutputStream#out
     */
    public DataOutputStream(OutputStream out) {
        super(out);
    }

    /**
     * 让written增加value,如果超过Integer.MAX_VALUE,written为  *Integer.MAX_VALUE
     */
    private void incCount(int value) {
        int temp = written + value;
        if (temp < 0) {
            temp = Integer.MAX_VALUE;
        }
        written = temp;
    }

    /**
     * 对特定的byte进行写 (参数b表示8个比特位表示的int数字) 到output stream中. 如果异常被抛出, 计数器written的值加1
     * <p>
     * 实现OutputStram的write方法
     *
     * @param      b   需要被写入的byte
     * @exception  如果发生I/O错误抛出I/O异常
     * @see        java.io.FilterOutputStream#out
     */
    public synchronized void write(int b) throws IOException {
        out.write(b);
        incCount(1);
    }

    /**
     * 从特定的byte数组中写入len个byte到output stream中,写入byte数组的起始位置为offset。如果异常抛出written的值将会增加到len
     *
     * @param      b     被写的byte数组
     * @param      off   起始位置.
     * @param      len   写入的byte个数.
     * @exception  如果发生I/O错误抛出I/O异常
     * @see        java.io.FilterOutputStream#out
     */
    public synchronized void write(byte b[], int off, int len)
        throws IOException
    {
        out.write(b, off, len);
        incCount(len);
    }

    /**
     * 将数据刷入output stream,强制将缓存中的任何数据写入到output stream
     * 
     * DataOutputStream 的flush方法中或调用其内含的output stream的flush方法
     * @exception  如果发生I/O错误抛出I/O异常
     * @see        java.io.FilterOutputStream#out
     * @see        java.io.OutputStream#flush()
     */
    public void flush() throws IOException {
        out.flush();
    }

    /**
     * 向内含的output stream写一个bool(相当于1的数据),如果v为true将写入1,false将写入0。如果没有任何异常抛出计数器written的值将会加1
     *
     * @param      v   被写入的bool值
     * @exception  如果发生I/O错误抛出I/O异常
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeBoolean(boolean v) throws IOException {
        out.write(v ? 1 : 0);
        incCount(1);
    }

    /**
     * 向内含的output stream写一个一个byte。如果没有任何异常抛出计数器written的值将会加1
     *
     * @param      v   被写入的值
     * @exception  如果发生I/O错误抛出I/O异常
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeByte(int v) throws IOException {
        out.write(v);
        incCount(1);
    }

    /**
     * 向内含的output stream写一个2个byte(1个short)。如果没有任何异常抛出计数器written的值将会加2
     *
     * @param      v   被写入的short值
     * @exception 如果发生I/O错误抛出I/O异常.
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeShort(int v) throws IOException {
        out.write((v >>> 8) & 0xFF);
        out.write((v >>> 0) & 0xFF);
        incCount(2);
    }

    /**
     * 写入一个char(2个byte), 先写入高位. 如果没有任何异常抛出计数器written的值将会加2.
     * 向
     * @param      v   被写入的char值
     * @exception  如果发生I/O错误抛出I/O异常.
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeChar(int v) throws IOException {
        out.write((v >>> 8) & 0xFF);
        out.write((v >>> 0) & 0xFF);
        incCount(2);
    }

    /**
     * 写入一个int(4个byte), 先写入高位. 如果没有任何异常抛出计数器written的值将会加4.
     * @param      v   被写入的int
     * @exception  如果发生I/O错误抛出I/O异常.
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeInt(int v) throws IOException {
        out.write((v >>> 24) & 0xFF);
        out.write((v >>> 16) & 0xFF);
        out.write((v >>>  8) & 0xFF);
        out.write((v >>>  0) & 0xFF);
        incCount(4);
    }

    private byte writeBuffer[] = new byte[8];

    /**
     * 写入一个long(8个byte), 先写入高位. 如果没有任何异常抛出计数器written的值将会加8.
     *
     * @param      v   a <code>long</code> to be written.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeLong(long v) throws IOException {
        writeBuffer[0] = (byte)(v >>> 56);
        writeBuffer[1] = (byte)(v >>> 48);
        writeBuffer[2] = (byte)(v >>> 40);
        writeBuffer[3] = (byte)(v >>> 32);
        writeBuffer[4] = (byte)(v >>> 24);
        writeBuffer[5] = (byte)(v >>> 16);
        writeBuffer[6] = (byte)(v >>>  8);
        writeBuffer[7] = (byte)(v >>>  0);
        out.write(writeBuffer, 0, 8);
        incCount(8);
    }

    /**
     * 通过Float的floatToIntBits方法将float参数转换为int,然后将这个int值写入到内含的output stream(占据4个byte的空间),如果没有任何异常抛出计数器written的值将会加4.
     * @param      v   被写入的float
     * @exception  如果发生I/O错误抛出I/O异常
     * @see        java.io.FilterOutputStream#out
     * @see        java.lang.Float#floatToIntBits(float)
     */
    public final void writeFloat(float v) throws IOException {
        writeInt(Float.floatToIntBits(v));
    }

    /**
     * 通过Double的doubleToLongBits方法将float参数转换为double,然后将这个double值写入到内含的output stream(占据8个byte的空间),如果没有任何异常抛出计数器written的值将会加8.
     * @param      v   被写入的double值
     * @exception  如果发生I/O错误抛出I/O异常.
     * @see        java.io.FilterOutputStream#out
     * @see        java.lang.Double#doubleToLongBits(double)
     */
    public final void writeDouble(double v) throws IOException {
        writeLong(Double.doubleToLongBits(v));
    }

    /**
     * 将字符串作为一个bytes序列写入到内含的output stream中。字符串中的字符被按顺序写入,通过丢弃它高位的8个bit。如果没有任何异常抛出计数器written的值将会增加字符串s的字符数组的长度
     * 
     * @param      s   
     * @exception  如果发生I/O错误抛出I/O异常.
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeBytes(String s) throws IOException {
        int len = s.length();
        for (int i = 0 ; i < len ; i++) {
            out.write((byte)s.charAt(i));
        }
        incCount(len);
    }

    /**
     * Writes a string to the underlying output stream as a sequence of
     * characters
     * 将字符串作为一个字符数组序列写入到内含的output stream对象中. 每一个字符像是调用了writeChar方法一样写入内含的output stream中.如果没有任何异常抛出计数器written的值将会增加字符串s的字符数组的长度
     *
     * @param      s   被写入的字符串
     * @exception  IOException 如果发生I/O错误抛出I/O异常.
     * @see        java.io.DataOutputStream#writeChar(int)
     * @see        java.io.FilterOutputStream#out
     */
    public final void writeChars(String s) throws IOException {
        int len = s.length();
        for (int i = 0 ; i < len ; i++) {
            int v = s.charAt(i);
            out.write((v >>> 8) & 0xFF);
            out.write((v >>> 0) & 0xFF);
        }
        incCount(len * 2);
    }

    /**
     * 
  将一个字符串以一种独立于机器的方法UTF-8编码,写入DataOutput对象中首先,2byte的数据会像调用writeShort方法一样写入到目标对象中,表示要追加的byte个数。这个值是真实被写出的byte的个数,而不是string字符串的字符个数,在这个长度之后,字符串中的每一个字符都是一个output,并按顺序排列,使用改良的UTF-8编码方法为每一个字符编码。如果没有任何异常抛出,计数器written将会增加output stream的byte总数的值,这个比特数将是原字符串字节数的最低二倍,最多三倍。
     *
     * @param      str   a string to be written.
     * @exception  IOException  if an I/O error occurs.
     */
    public final void writeUTF(String str) throws IOException {
        writeUTF(str, this);
    }

    /**
     * 将一个字符串以一种独立于机器的方法UTF-8编码,写入DataOutput对象中首先,2byte的数据会像调用writeShort方法一样写入到目标对象中,表示要追加的byte个数。这个值是真实被写出的byte的个数,而不是string字符串的字符个数,在这个长度之后,字符串中的每一个字符都是一个output,并按顺序排列,使用改良的UTF-8编码方法为每一个字符编码。如果没有任何异常抛出,计数器written将会增加output stream的byte总数的值,这个比特数将是原字符串字节数的最低二倍,最多三倍。
     * @param      str   被写入的字符串
     * @param      out   目标写入对象
     * @return     写出的byte数
     * @exception  IOException  如果为发生I/O错误
     */
    static int writeUTF(String str, DataOutput out) throws IOException {
        int strlen = str.length();
        int utflen = 0;
        int c, count = 0;

        /* use charAt instead of copying String to char array */
        for (int i = 0; i < strlen; i++) {
            c = str.charAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) {
                utflen++;
            } else if (c > 0x07FF) {
                utflen += 3;
            } else {
                utflen += 2;
            }
        }

        if (utflen > 65535)
            throw new UTFDataFormatException(
                "encoded string too long: " + utflen + " bytes");

        byte[] bytearr = null;
        if (out instanceof DataOutputStream) {
            DataOutputStream dos = (DataOutputStream)out;
            if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
                dos.bytearr = new byte[(utflen*2) + 2];
            bytearr = dos.bytearr;
        } else {
            bytearr = new byte[utflen+2];
        }

        bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
        bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);

        int i=0;
        for (i=0; i<strlen; i++) {
           c = str.charAt(i);
           if (!((c >= 0x0001) && (c <= 0x007F))) break;
           bytearr[count++] = (byte) c;
        }

        for (;i < strlen; i++){
            c = str.charAt(i);
            if ((c >= 0x0001) && (c <= 0x007F)) {
                bytearr[count++] = (byte) c;

            } else if (c > 0x07FF) {
                bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
                bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
                bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
            } else {
                bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
                bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
            }
        }
        out.write(bytearr, 0, utflen+2);
        return utflen + 2;
    }

    /**
     * 返回计数器written的当前值,即当前被写入到output stream中的字符数.
     * 如果计数器的值溢出,它将会被赋值为Integer.MAX_VALUE.
     *
     * @return  written字段的值
     * @see     java.io.DataOutputStream#written
     */
    public final int size() {
        return written;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值