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\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(數據輸入流)的認知、源碼和示例"

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM