skywang12345

导航

 

本章介绍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\n", byteToHexString((byte)0x8F));
 69             System.out.printf("charToHexString(0x8FCF):0x%s\n", charToHexString((char)0x8FCF));
 70 
 71             System.out.printf("readBoolean():%s\n", in.readBoolean());
 72             System.out.printf("readByte():0x%s\n", byteToHexString(in.readByte()));
 73             System.out.printf("readChar():0x%s\n", charToHexString(in.readChar()));
 74             System.out.printf("readShort():0x%s\n", shortToHexString(in.readShort()));
 75             System.out.printf("readInt():0x%s\n", Integer.toHexString(in.readInt()));
 76             System.out.printf("readLong():0x%s\n", Long.toHexString(in.readLong()));
 77             System.out.printf("readUTF():%s\n", 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(数据输入流)的认知、源码和示例"

 

posted on 2013-11-01 09:14  如果天空不死  阅读(13923)  评论(0编辑  收藏  举报