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

2023-11-11

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

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;
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JAVA常用类(IO篇)-DataOutputStream详解 的相关文章

随机推荐

  • 分库分表的概念

    目录 一 分库分表有什么用 二 分库分表的方式 三 分库分表的缺点 四 什么时候需要分库分表 五 常见的分库分表组件 总结 在前面写了一篇关于MySQL主从集群的文章 而主从的作用 在我们开发角度更大的作用是作为读写分离的支持 也是学习Sh
  • Debian系统下network和NetworkManager冲突及关闭NetworkManager

    在Debian Linux下 network服务管理对于网卡的配置 NetworkManager是由管理系统网络链接的服务和允许用户管理网络连接的客户端服务组成 network和NetworkManager服务会出现冲突 一般如果想另外使用
  • [前端系列第7弹]Vue:一个渐进式的 JavaScript 框架

    Vue 是一个用于构建用户界面的 JavaScript 框架 它具有以下特点 渐进式 Vue 可以根据不同的使用场景 灵活地选择使用库或者框架的方式 从而实现渐进式的开发 响应式 Vue 通过数据绑定和虚拟 DOM 技术 实现了高效的响应式
  • ajax数字的正则表达式,validateform正则表达式 datatype验证数字

    第8章 用户模式下的线程同步 4 lowbar 条件变量 Condition Variable 8 6 条件变量 Condition Variables 可利用临界区或SRWLock锁来实现 8 6 1 条件变量的使用 1 条件变量机制就是
  • BigDecimal转化为String

    Oracle Java字段类型转换 从数据库取出一个字段 在java中为BigDecimal类型 将其转化为String类型的字段时 报转化异常的错误java math BigDecimal cannot be cast to java l
  • Spring面试题整理

    Spring的优缺点是什么 优点 1 方便解耦 简化开发 Spring就是一个大工厂 可以将所有对象的创建和依赖关系的维护 交给Spring管理 2 AOP编程的支持 Spring提供面向切面编程 可以方便的实现对程序进行权限拦截 运行监控
  • WRF系列教程1:WRF如何得到更好的模拟结果?

    编者按 这是新开的一个系列 有时间会逐步将WRF官方培训的ppt挑选个人认为重要的进行翻译 以及结合个人的使用经验进行一些解释 由于个人水平有限 难免会出现偏差和错误 欢迎斧正 本篇内容来源于WRF官网2021年的培训ppt Applica
  • 如何用frp做内网穿透

    使用场景 需要将内网的一些应用端口开放出来 以便可以通过外网访问或者第三方调试使用 采用工具 frp 0 28 0 linux amd64 tar gz 工具下载地址 https github com fatedier frp releas
  • element 实现表格滚动vue-seamless-scroll --save

    npm install vue seamless scroll save main js import scroll from vue seamless scroll Vue use scroll
  • 服务器扩容 --挂载磁盘方式(学习笔记)

    一 查看服务器磁盘 df h fdisk l 可以看到新增加了一块硬盘 dev sdb 大概有4T的容量 二 挂载磁盘 1 进行磁盘分区 fdisk dev sdb sdb为新加磁盘名称 步骤如下 2 查看新建分区 fdisk l 3 对新
  • create connection SQLException, url: jdbc:mysql://localhost:3306/users?characterEncoding=utf-8, erro

    今天写JDBCTemplate的时候出现bug 一开始网上查的时候说可能是驱动版本和数据库版本不太对 但是后来手写连接用DriverManager获取连接是可以获取得到的 然后又用Druid连接池试了一下 也可以获取连接 所以排除这个问题
  • BP脑电数据处理

    BP Brain Products 脑电数据处理 一 BP分析软件导出数据 标签 1 1 BP分析软件加载原始数据 1 2导出Markers 1 3 将原始数据导出成edf格式输出 1 4 MATLAB处理 一 BP分析软件导出数据 标签
  • [机缘参悟-92]:《本质思考》- 本质思考的9种训练方法

    目录 前言 01 假设力 尽可能涵盖所有的可能方案 02 逆向思考力 从未来可能的失败倒推 03 共情力 不断地站在他人的角度看问题 04 信息整理力 辨别每种信息的类型和属性和背后意图 05 图像化能力 掌握更直观的表达方式 06 定规则
  • 电子电路图中VCC、IO、3V3OUT、VDD3V3解释

    1 Vcc 一般表示电源正端 是晶体管集电极或IC集电极供电电压 2 IO 输入 输出端口 3 3V3OUT 3 3V输出端 4 VDD 一般表示电源正端 是场效应管漏极或IC内漏极供电电压 5 3V3 3 3V端 一般是供电电压为3 3V
  • 【Django缓存实现】前端缓存和后端缓存

    目录 一 什么是缓存 二 Web缓存 一 前端缓存 二 后端缓存 三 Django缓存 一 缓存类型 二 设置缓存 1 Memcached 2 Redis 3 数据库缓存 4 文件系统缓存 5 本地内存缓存 6 虚拟缓存 用于开发模式 7
  • Windows 环境配置Github 的SSH key

    今天需要将本机编写的代码提交至github 上 但是push 远程分支提示如下错误信 remote Support for password authentication was removed on August 13 2021 Plea
  • usaco-Cow Pedigrees

    题意 求出n个节点可以构成多少种高为h的二叉树 分析 设左子树节点数x 右子树节点数为n x 1 函数dp表示满足条件的树的个数 则dp n dp x n x 1 对于未知数h dp n dp x dp n x 1 x lt n 2 x i
  • llvm和clang环境配置(续篇)

    关于llvm和clang开发环境的配置之前已经发过一篇 当时是因为llvm官网给的文档省略了很多重要信息 需要额外补充一些信息才能完成环境配置 时隔许久 重新打开llvm官网 发现他们的文档已经更新了 写的非常详细 专门列举了一节用来解释如
  • Java 集合 --- HashMap的底层原理

    Java 集合 HashMap的底层原理 HashMap的下标计算 计算步骤 为什么要 h h gt gt gt 16 为什么数组长度必须是 2 n HashMap的树化 HashMap的扩容 HashMap的put流程 HashMap的线
  • JAVA常用类(IO篇)-DataOutputStream详解

    文方便阅读和理解 本文翻译自源码 适合具有一定数据结构 算法基础且有志专研源码的朋友阅读 初学者请无视 错漏之处 多谢指正 package java io DataOutputStream 可以实现java对象到流的便捷写入 一个应用可以随