zoukankan      html  css  js  c++  java
  • java io系列15之 DataOutputStream(数据输出流)的认知、源码和示例

    本章介绍DataOutputStream。我们先对DataOutputStream有个大致认识,然后再深入学习它的源码,最后通过示例加深对它的了解。

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_15.html

    DataOutputStream 介绍

    DataOutputStream 是数据输出流。它继承于FilterOutputStream。
    DataOutputStream 是用来装饰其它输出流,将DataOutputStream和DataInputStream输入流配合使用,“允许应用程序以与机器无关方式从底层输入流中读写基本 Java 数据类型”。

    DataOutputStream 源码分析(基于jdk1.7.40)

    复制代码
      1 package java.io;
      2 
      3 public class DataOutputStream extends FilterOutputStream implements DataOutput {
      4     // “数据输出流”的字节数
      5     protected int written;
      6 
      7     // “数据输出流”对应的字节数组
      8     private byte[] bytearr = null;
      9 
     10     // 构造函数
     11     public DataOutputStream(OutputStream out) {
     12         super(out);
     13     }
     14 
     15     // 增加“输出值”
     16     private void incCount(int value) {
     17         int temp = written + value;
     18         if (temp < 0) {
     19             temp = Integer.MAX_VALUE;
     20         }
     21         written = temp;
     22     }
     23 
     24     // 将int类型的值写入到“数据输出流”中
     25     public synchronized void write(int b) throws IOException {
     26         out.write(b);
     27         incCount(1);
     28     }
     29 
     30     // 将字节数组b从off开始的len个字节,都写入到“数据输出流”中
     31     public synchronized void write(byte b[], int off, int len)
     32         throws IOException
     33     {
     34         out.write(b, off, len);
     35         incCount(len);
     36     }
     37 
     38     // 清空缓冲,即将缓冲中的数据都写入到输出流中
     39     public void flush() throws IOException {
     40         out.flush();
     41     }
     42 
     43     // 将boolean类型的值写入到“数据输出流”中
     44     public final void writeBoolean(boolean v) throws IOException {
     45         out.write(v ? 1 : 0);
     46         incCount(1);
     47     }
     48 
     49     // 将byte类型的值写入到“数据输出流”中
     50     public final void writeByte(int v) throws IOException {
     51         out.write(v);
     52         incCount(1);
     53     }
     54 
     55     // 将short类型的值写入到“数据输出流”中
     56     // 注意:short占2个字节
     57     public final void writeShort(int v) throws IOException {
     58         // 写入 short高8位 对应的字节
     59         out.write((v >>> 8) & 0xFF);
     60         // 写入 short低8位 对应的字节
     61         out.write((v >>> 0) & 0xFF);
     62         incCount(2);
     63     }
     64 
     65     // 将char类型的值写入到“数据输出流”中
     66     // 注意:char占2个字节
     67     public final void writeChar(int v) throws IOException {
     68         // 写入 char高8位 对应的字节
     69         out.write((v >>> 8) & 0xFF);
     70         // 写入 char低8位 对应的字节
     71         out.write((v >>> 0) & 0xFF);
     72         incCount(2);
     73     }
     74 
     75     // 将int类型的值写入到“数据输出流”中
     76     // 注意:int占4个字节
     77     public final void writeInt(int v) throws IOException {
     78         out.write((v >>> 24) & 0xFF);
     79         out.write((v >>> 16) & 0xFF);
     80         out.write((v >>>  8) & 0xFF);
     81         out.write((v >>>  0) & 0xFF);
     82         incCount(4);
     83     }
     84 
     85     private byte writeBuffer[] = new byte[8];
     86 
     87     // 将long类型的值写入到“数据输出流”中
     88     // 注意:long占8个字节
     89     public final void writeLong(long v) throws IOException {
     90         writeBuffer[0] = (byte)(v >>> 56);
     91         writeBuffer[1] = (byte)(v >>> 48);
     92         writeBuffer[2] = (byte)(v >>> 40);
     93         writeBuffer[3] = (byte)(v >>> 32);
     94         writeBuffer[4] = (byte)(v >>> 24);
     95         writeBuffer[5] = (byte)(v >>> 16);
     96         writeBuffer[6] = (byte)(v >>>  8);
     97         writeBuffer[7] = (byte)(v >>>  0);
     98         out.write(writeBuffer, 0, 8);
     99         incCount(8);
    100     }
    101 
    102     // 将float类型的值写入到“数据输出流”中
    103     public final void writeFloat(float v) throws IOException {
    104         writeInt(Float.floatToIntBits(v));
    105     }
    106 
    107     // 将double类型的值写入到“数据输出流”中
    108     public final void writeDouble(double v) throws IOException {
    109         writeLong(Double.doubleToLongBits(v));
    110     }
    111 
    112     // 将String类型的值写入到“数据输出流”中
    113     // 实际写入时,是将String对应的每个字符转换成byte数据后写入输出流中。
    114     public final void writeBytes(String s) throws IOException {
    115         int len = s.length();
    116         for (int i = 0 ; i < len ; i++) {
    117             out.write((byte)s.charAt(i));
    118         }
    119         incCount(len);
    120     }
    121 
    122     // 将String类型的值写入到“数据输出流”中
    123     // 实际写入时,是将String对应的每个字符转换成char数据后写入输出流中。
    124     public final void writeChars(String s) throws IOException {
    125         int len = s.length();
    126         for (int i = 0 ; i < len ; i++) {
    127             int v = s.charAt(i);
    128             out.write((v >>> 8) & 0xFF);
    129             out.write((v >>> 0) & 0xFF);
    130         }
    131         incCount(len * 2);
    132     }
    133 
    134     // 将UTF-8类型的值写入到“数据输出流”中
    135     public final void writeUTF(String str) throws IOException {
    136         writeUTF(str, this);
    137     }
    138 
    139     // 将String数据以UTF-8类型的形式写入到“输出流out”中
    140     static int writeUTF(String str, DataOutput out) throws IOException {
    141         //获取String的长度
    142         int strlen = str.length();
    143         int utflen = 0;
    144         int c, count = 0;
    145 
    146         // 由于UTF-8是1~4个字节不等;
    147         // 这里,根据UTF-8首字节的范围,判断UTF-8是几个字节的。
    148         for (int i = 0; i < strlen; i++) {
    149             c = str.charAt(i);
    150             if ((c >= 0x0001) && (c <= 0x007F)) {
    151                 utflen++;
    152             } else if (c > 0x07FF) {
    153                 utflen += 3;
    154             } else {
    155                 utflen += 2;
    156             }
    157         }
    158 
    159         if (utflen > 65535)
    160             throw new UTFDataFormatException(
    161                 "encoded string too long: " + utflen + " bytes");
    162 
    163         // 新建“字节数组bytearr”
    164         byte[] bytearr = null;
    165         if (out instanceof DataOutputStream) {
    166             DataOutputStream dos = (DataOutputStream)out;
    167             if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
    168                 dos.bytearr = new byte[(utflen*2) + 2];
    169             bytearr = dos.bytearr;
    170         } else {
    171             bytearr = new byte[utflen+2];
    172         }
    173 
    174         // “字节数组”的前2个字节保存的是“UTF-8数据的长度”
    175         bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
    176         bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
    177 
    178         // 对UTF-8中的单字节数据进行预处理
    179         int i=0;
    180         for (i=0; i<strlen; i++) {
    181            c = str.charAt(i);
    182            if (!((c >= 0x0001) && (c <= 0x007F))) break;
    183            bytearr[count++] = (byte) c;
    184         }
    185 
    186         // 对预处理后的数据,接着进行处理
    187         for (;i < strlen; i++){
    188             c = str.charAt(i);
    189             // UTF-8数据是1个字节的情况
    190             if ((c >= 0x0001) && (c <= 0x007F)) {
    191                 bytearr[count++] = (byte) c;
    192 
    193             } else if (c > 0x07FF) {
    194                 // UTF-8数据是3个字节的情况
    195                 bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
    196                 bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));
    197                 bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
    198             } else {
    199                 // UTF-8数据是2个字节的情况
    200                 bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));
    201                 bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));
    202             }
    203         }
    204         // 将字节数组写入到“数据输出流”中
    205         out.write(bytearr, 0, utflen+2);
    206         return utflen + 2;
    207     }
    208 
    209     public final int size() {
    210         return written;
    211     }
    212 }
    复制代码

    示例代码

    关于DataOutStream中API的详细用法,参考示例代码(DataInputStreamTest.java)

    复制代码
      1 import java.io.DataInputStream;
      2 import java.io.DataOutputStream;
      3 import java.io.ByteArrayInputStream;
      4 import java.io.File;
      5 import java.io.InputStream;
      6 import java.io.FileInputStream;
      7 import java.io.FileOutputStream;
      8 import java.io.IOException;
      9 import java.io.FileNotFoundException;
     10 import java.lang.SecurityException;
     11 
     12 /**
     13  * DataInputStream 和 DataOutputStream测试程序
     14  *
     15  * @author skywang
     16  */
     17 public class DataInputStreamTest {
     18 
     19     private static final int LEN = 5;
     20 
     21     public static void main(String[] args) {
     22         // 测试DataOutputStream,将数据写入到输出流中。
     23         testDataOutputStream() ;
     24         // 测试DataInputStream,从上面的输出流结果中读取数据。
     25         testDataInputStream() ;
     26     }
     27 
     28     /**
     29      * DataOutputStream的API测试函数
     30      */
     31     private static void testDataOutputStream() {
     32 
     33         try {
     34             File file = new File("file.txt");
     35             DataOutputStream out =
     36                   new DataOutputStream(
     37                       new FileOutputStream(file));
     38 
     39             out.writeBoolean(true);
     40             out.writeByte((byte)0x41);
     41             out.writeChar((char)0x4243);
     42             out.writeShort((short)0x4445);
     43             out.writeInt(0x12345678);
     44             out.writeLong(0x0FEDCBA987654321L);
     45 
     46             out.writeUTF("abcdefghijklmnopqrstuvwxyz严12");
     47 
     48             out.close();
     49        } catch (FileNotFoundException e) {
     50            e.printStackTrace();
     51        } catch (SecurityException e) {
     52            e.printStackTrace();
     53        } catch (IOException e) {
     54            e.printStackTrace();
     55        }
     56     }
     57     /**
     58      * DataInputStream的API测试函数
     59      */
     60     private static void testDataInputStream() {
     61 
     62         try {
     63             File file = new File("file.txt");
     64             DataInputStream in =
     65                   new DataInputStream(
     66                       new FileInputStream(file));
     67 
     68             System.out.printf("byteToHexString(0x8F):0x%s
    ", byteToHexString((byte)0x8F));
     69             System.out.printf("charToHexString(0x8FCF):0x%s
    ", charToHexString((char)0x8FCF));
     70 
     71             System.out.printf("readBoolean():%s
    ", in.readBoolean());
     72             System.out.printf("readByte():0x%s
    ", byteToHexString(in.readByte()));
     73             System.out.printf("readChar():0x%s
    ", charToHexString(in.readChar()));
     74             System.out.printf("readShort():0x%s
    ", shortToHexString(in.readShort()));
     75             System.out.printf("readInt():0x%s
    ", Integer.toHexString(in.readInt()));
     76             System.out.printf("readLong():0x%s
    ", Long.toHexString(in.readLong()));
     77             System.out.printf("readUTF():%s
    ", in.readUTF());
     78 
     79             in.close();
     80        } catch (FileNotFoundException e) {
     81            e.printStackTrace();
     82        } catch (SecurityException e) {
     83            e.printStackTrace();
     84        } catch (IOException e) {
     85            e.printStackTrace();
     86        }
     87     }
     88 
     89     // 打印byte对应的16进制的字符串
     90     private static String byteToHexString(byte val) {
     91         return Integer.toHexString(val & 0xff);
     92     }
     93 
     94     // 打印char对应的16进制的字符串
     95     private static String charToHexString(char val) {
     96         return Integer.toHexString(val);
     97     }
     98 
     99     // 打印short对应的16进制的字符串
    100     private static String shortToHexString(short val) {
    101         return Integer.toHexString(val & 0xffff);
    102     }
    103 }
    复制代码

    运行结果

    byteToHexString(0x8F):0x8f
    charToHexString(0x8FCF):0x8fcf
    readBoolean():true
    readByte():0x41
    readChar():0x4243
    readShort():0x4445
    readInt():0x12345678
    readLong():0xfedcba987654321
    readUTF():abcdefghijklmnopqrstuvwxyz严12

    结果说明

    参考"java io系列14之 DataInputStream(数据输入流)的认知、源码和示例"

  • 相关阅读:
    【Codeforces Round #240 (Div. 1) 】E—Mashmokh's Designed Problem(Spaly)
    【Codeforces Round #240 (Div. 1) 】E—Mashmokh's Designed Problem(Spaly)
    拦路虎
    拦路虎:jQuery
    图片百分百问题 z-index问题
    惠头无忧——浏览器兼容性
    响应式设计
    老子的第一篇博客
    less 学习 (计划终于执行了啊,不再拖延了)
    工作拦路虎
  • 原文地址:https://www.cnblogs.com/shangxiaofei/p/3844030.html
Copyright © 2011-2022 走看看