数据流DataInput(Output)Stream 和 字节数组流 ByteArrayInput(Output) Stream
一, 1個網(wǎng)絡(luò)傳輸模型
在一個網(wǎng)絡(luò)傳輸模型中.
假如1個電腦A想把1個double類型的值12345.678 傳給另1個網(wǎng)絡(luò)另一端的電腦B.?
要如何實現(xiàn)呢?
大概分成幾個步驟.
1. 轉(zhuǎn)為字節(jié)數(shù)組(電腦A).
無論網(wǎng)絡(luò)上兩個終端要傳輸什么類型的數(shù)據(jù), 實際在網(wǎng)線上傳輸?shù)亩际?進制數(shù)據(jù)(bit).
所以電腦A是不能直接把1個double類型傳送出去的.?? 必須將double類型的值12345.678的值轉(zhuǎn)換為字節(jié)類型(16個bit).
將1個double類型轉(zhuǎn)換為字節(jié)類型并不簡單, 這設(shè)計編碼的問題, 但是java能把這些都封裝好了.
而1個double類型的數(shù)據(jù)并不是1個字節(jié)就能存放的, double類型長度是64位啊, 所以就需要1個64位長度的字節(jié)數(shù)組才能完整存放1個float類型的數(shù)據(jù).
有人問,既然網(wǎng)絡(luò)上傳送的是位(bit), 為何不直接把變量轉(zhuǎn)化為bit類型.
答案很簡單, 絕大部分計算機的內(nèi)存的最小單位(1個地址)是8 bit,?? 所以大部分編程語言, 例如c/c++, java等所有變量最小長度就是8bit(1個字節(jié)).
所以無論傳輸什么類型的變量, 都需要把變量的數(shù)據(jù)轉(zhuǎn)為字節(jié)數(shù)據(jù), 然后存放在1個字節(jié)數(shù)組中.
2. 將字節(jié)數(shù)組打包(電腦A).
為了盡量減少網(wǎng)絡(luò)上傳輸?shù)臄?shù)據(jù)大小,? 我們通常要把要傳輸?shù)淖止?jié)數(shù)組打成1個壓縮數(shù)據(jù)包. 本文不會詳細討論這點.
3. 傳輸數(shù)據(jù)包(網(wǎng)絡(luò)).
這樣, 在網(wǎng)絡(luò)上傳輸?shù)膶嶋H就是數(shù)據(jù)包了.?? 本文不會詳細討論這點.
4. 解壓數(shù)據(jù)包得到字節(jié)數(shù)組(電腦B)
電腦B 接受到數(shù)據(jù)包后, 就需要解壓數(shù)據(jù)包得到1里面封裝的字節(jié)數(shù)組. 本文不會詳細討論這點.
5. 將字節(jié)數(shù)組里的數(shù)據(jù)轉(zhuǎn)換為原始類型(double)(電腦B)
電腦B 最后還要把該字節(jié)數(shù)組的數(shù)據(jù)轉(zhuǎn)換為原來的類型double, 才真正得到由電腦A傳過來的float類型的值.
如下圖
二, 將1個double變量轉(zhuǎn)化為1個字節(jié)數(shù)組
上一節(jié)提過了, 本文的重點在于基本變量和字節(jié)數(shù)組的轉(zhuǎn)換.
有人覺得數(shù)據(jù)類型的轉(zhuǎn)化很基礎(chǔ), 但是實際上java并沒有提供1個封裝好的方法, 例如 xxx.toByteArray(Double d) 就返回1個字節(jié)數(shù)組.. 除非你自己寫.
致使是double基本類型的封裝類Double, 也沒有提供轉(zhuǎn)換為ByteArray的方法.
Double類里有1個類似的byteValue(), 但是返回的只是1個Byte, 實際上只取double變量的低8位. 高位的字節(jié)數(shù)據(jù)都被截掉了..
自己寫1個int類型轉(zhuǎn)換為1個ByteArray是可行的, 因為我們知道Java中int類型的編碼是補碼, 但是要用到位運算.
例如:
public static byte[] intToBytes2(int n){ byte[] b = new byte[4]; for(int i = 0;i < 4;i++){ b[i] = (byte)(n >> (24 - i * 8)); } return b; }
但是double的編碼遠比int復雜, 必須要用另外的方法來編寫.
而且這樣的話違背了Java的最大優(yōu)勢和本質(zhì):
Java讓程序猿focus on business, 并不需要關(guān)心數(shù)據(jù)在內(nèi)存里是怎樣存儲的.
有沒有一種方法, 可以接受各種基本類型參數(shù), 轉(zhuǎn)換為字節(jié)數(shù)組? 上面說過了, Java沒有提供.
但是Java提供兩個流, 它們嵌套使用的話, 就相當于實現(xiàn)了上面所說的功能, 將各種基本類型轉(zhuǎn)換為字節(jié)數(shù)組.
它們就是DataOutputStream 和 ByteArrayOutputStream
2.1 ByteArrayOutputStream
我們知道FlieOutputStream是1個指向文件的的字節(jié)流,? 同樣地, ByteArrayOutputStream 也可以理解為1個指向1個ByteArray的字節(jié)流.
我們可以同個這個流添加字節(jié)數(shù)據(jù)到1個字節(jié)數(shù)組.
2.1.1 構(gòu)造方法
有必要提提這個ByteArrayOutputStream的構(gòu)造方法.
既然是指向ByteArray的流, 必然要有1個core 字節(jié)數(shù)組(目標數(shù)組).
例如FileOutputStream
有1個構(gòu)造方法是
new FileOutputStream(File f)作為參數(shù),我們必須制定文件輸出字節(jié)流的目標文件
而對于ByteArrayOutputStream,
則沒有
new ByteArrayOutputStream(byte[] b)也就是講我們不能指定數(shù)組ouput字節(jié)流的目標字節(jié)數(shù)組.
實際上, 對于ByteArrayOutputStream來講,目標字節(jié)數(shù)組是builded in的, 也就是它對于程序猿是隱藏的.
但是它提供了另1個方法
toByteArray() , 這個方法new了1個新的字節(jié)數(shù)組對象, 然后把隱藏的目標字節(jié)數(shù)組的數(shù)據(jù)復制到的這個新的字節(jié)數(shù)組內(nèi).
也就是說返回1個隱藏字節(jié)數(shù)組的副本.
而這個流提供了另1個構(gòu)造方法
參數(shù)只能用于指定緩沖區(qū)大小.
具體看看本節(jié)的例子.
2.1.2 write方法
ByteArrayOutputStream 的成員方法 和 FileOutputStream 很類似.
都具有
write(int)? 寫1個字節(jié)
write(byte[]) 寫1個字節(jié)數(shù)組
函數(shù)
但根據(jù)本文, 很明顯我們需要的是 write(double)這個方法, 但是 ByteArrayOutputStream只是1個原始的字節(jié)流, 并沒有提供.
所以我們需要1個額外的包裹流.
2.2 DataOutputStream
跟上面那個流不同,? DataOutputStream不能理解為指向"Data"的字節(jié)流.
實際上DataOutputStream是處理流(包裹流)的一種, 必須基于1個原始流之上.
DataOutputStream 提供的方法就強大得多了.
例如:
writeFloat(float f)?? 寫入1個float到流中.
writeLong(long l)?? 寫入1個long類型到流中
writeDouble(double d)? 寫入1個double類型到流中
....
可見, DataOutputStream實際提供了各種將基本類型寫入到字節(jié)流的1種渠道. 包裹ByteArrayOutputStream的話就能轉(zhuǎn)換為字節(jié)數(shù)組.
而writeDouble(double d)方法正是我們需要的.
2.3 1個把double對象轉(zhuǎn)換為字節(jié)數(shù)組的例子
private static byte[] Send(double f) throws IOException{byte[] bArr = new byte[64];//the core byteArray is built in. and the 1024 is buffer sizeByteArrayOutputStream bos = new ByteArrayOutputStream(1024);DataOutputStream dos = new DataOutputStream(bos);dos.writeDouble(f);//this method will create a new byte[] objectbArr = bos.toByteArray();dos.close(); // bos will be cloased cascadereturn bArr; }上面的send方法就是接受1個double f,并返回對應的字節(jié)數(shù)組.
這個就是上面模型電腦A在第一步完成的事情
三, 從字節(jié)數(shù)組內(nèi)提取1個double類型
這個步驟是上面模型的電腦B的最后一步, 實際上就是上面第二節(jié)的逆行為.
那么到底如何從網(wǎng)絡(luò)上接收到的字節(jié)數(shù)組提取1個double類型?
同樣地, java也沒有提供現(xiàn)成的方法.
道理是樣的,
我們一樣可以利用DataInputStream 和 ByteArrayInputStream 來見建立一條從字節(jié)數(shù)組到程序的輸入字節(jié)流.
如果弄懂了上面第二節(jié)(Output), 那么這個Input的原理也不難理解. 把write替換成read就ok了.
下面例子就是把 1個字節(jié)數(shù)組轉(zhuǎn)為double類型的方法:
private static double Get(byte[] bArr) throws IOException{double f;ByteArrayInputStream bis = new ByteArrayInputStream(bArr);DataInputStream dis = new DataInputStream(bis);f = dis.readDouble();dis.close();return f;}四, 結(jié)合上面兩個方法的簡單程序
下面程序是這樣的.
就是模擬本文一開始的模型,
一段發(fā)送1個double, 利用Send方法轉(zhuǎn)換為 字節(jié)數(shù)組, 然后利用Get方法還原為double類型.
最后輸出還原后的double類型..
import java.io.*;public class DataStream1{public static void f(){double fi = 12345.678;double fo = 0;byte[] bSend;byte[] bGet;try{bSend = Send(fi);//network.........bGet = bSend;fo = Get(bGet);}catch(IOException e){e.printStackTrace();}System.out.printf("fo is %f\n",fo); }private static byte[] Send(double f) throws IOException{byte[] bArr = new byte[64];//the core byteArray is built in. and the 1024 is buffer sizeByteArrayOutputStream bos = new ByteArrayOutputStream(1024);DataOutputStream dos = new DataOutputStream(bos);dos.writeDouble(f);//this method will create a new byte[] objectbArr = bos.toByteArray();dos.close(); // bos will be cloased cascadereturn bArr; }private static double Get(byte[] bArr) throws IOException{double f;ByteArrayInputStream bis = new ByteArrayInputStream(bArr);DataInputStream dis = new DataInputStream(bis);f = dis.readDouble();dis.close();return f;} }輸出:
gateman@TPEOS Java_1 $ ant Buildfile: /media/store1/Studies/Java/java_start/Java_1/build.xmlmain:[javac] /media/store1/Studies/Java/java_start/Java_1/build.xml:10: warning: 'includeantruntime' was not set, defaulting to build.sysclasspath=last; set to false for repeatable builds[javac] Compiling 1 source file to /media/store1/Studies/Java/java_start/Java_1/build/classes[java] fo is 12345.678000BUILD SUCCESSFUL Total time: 1 second
總結(jié)
以上是生活随笔為你收集整理的数据流DataInput(Output)Stream 和 字节数组流 ByteArrayInput(Output) Stream的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 缓冲流简介及简单用法
- 下一篇: Java 转换流 简介