Java_IO字符流和字節流

最近在android開發用到藍牙,因爲項目是對一些通訊協議進行解析,用到些IO字節流的知識,在這裏做個總結。

Java IO裏面要分清楚兩個基本概念,即字符流和字節流。

先來看一下流的概念:

在程序中所有的數據都是以流的方式進行傳輸或保存的,程序需要數據的時候要使用輸入流讀取數據,而當程序需要將一些數據保存起來的時候,就要使用輸出流完成。

程序中的輸入輸出都是以流的形式保存的,流中保存的實際上全都是字節文件。

網上這方面的文章很多,這篇主要介紹解析協議時用到的IO知識。在java.io包中操作文件內容的主要有兩大類:字節流、字符流。

在我的程序裏面,藍牙連上之後協議在傳輸過程中是以字節形式進行傳輸,因此本篇博客將主要介紹字節流。

字節流:

InputStream的API
 
1、public int read()
從輸入流讀取下一個數據字節。返回 0 到 255 範圍內的 int 字節值。如果因已到達流末尾而沒有可用的字節,則返回值 -1。
 
2、public int read(byte[] b)
從輸入流中讀取一定數量的字節並將其存儲在緩衝區數組 b 中。以整數形式返回實際讀取的字節數。如果因爲流位於文件末尾而沒有可用的字節,則返回值 -1;否則,至少可以讀取一個字節並將其存儲在 b 中。此方法等同於read(b, 0, b.length)
 
3、public int read(byte[] b, int off, int len)
將輸入流中最多 len 個數據字節讀入字節數組。嘗試讀取多達 len 字節,但可能讀取較少數量。以整數形式返回實際讀取的字節數。如果由於已到達流末尾而不再有數據,則返回 -1。
參數:
b - 讀入數據的緩衝區。
off - 在其處寫入數據的數組 b 的初始偏移量。
len - 要讀取的最大字節數。
 
OutputStream的API
 
1、public void write(int b)
將指定的字節寫入此輸出流。write 的常規協定是:向輸出流寫入一個字節。要寫入的字節是參數 b 的八個低位。b 的 24 個高位將被忽略。
 
2、public void write(byte[] b)
將 b.length 個字節從指定的字節數組寫入此輸出流。write(b) 的常規協定是:應該與調用 write(b, 0, b.length) 的效果完全相同。
 
3、public void write(byte[] b,
                  int off,
                  int len)
將指定字節數組中從偏移量 off 開始的 len 個字節寫入此輸出流。write(b, off, len) 的常規協定是:將數組 b 中的某些字節按順序寫入輸出流;元素 b[off] 是此操作寫入的第一個字節,b[off+len-1] 是此操作寫入的最後一個字節。
參數:
b - 數據。
off - 數據中的初始偏移量。
len - 要寫入的字節數。
 
4、public void flush()
刷新此輸出流並強制寫出所有緩衝的輸出字節。flush 的常規協定是:如果此輸出流的實現已經緩衝了以前寫入的任何字節,則調用此方法指示應將這些字節立即寫入它們預期的目標。
 

例子

在字節流中輸出數據主要是使用OutputStream完成,輸入使的是InputStream。


InputStream in = null;
OutputStream out = null;
try{
in = btSocket.getInputStream();
out = btSocket.getOutputStream();
}catch(IOException e){
}

接下來用in.read(buf, length)方法便可讀到字節流。out.write(buf)方法可以將字節輸出。這裏的buf是一個byte數組,在使用字節流的過程中,byte數組是非常常用,使用方法參考如下:


byte[] test = new byte[2];
test[0] = (byte)0xfd;
test[1] = (byte)0x55;

 

進制轉換

對字節進行操作時,有幾個操作非常實用。

1.  十六進制轉十進制 byteToInteger。

2.  十進制轉十六進制 integerToByte。

3.   String轉十六進制 StringToBytes。

4.   十六進制轉String bytesToHexString。

代碼分別如下:


int byteToInteger(byte b)
{
int value;
value = b & 0xff;
return value;
}

 


byte integerToByte(int a)
{
byte b;
b = (byte)(a & 0xFF);

return b;
}

因爲Java裏面byte是有符號數,一個字節8位,其中最左邊的位數代表符號位。因此byte值範圍爲-128~127,而int是32位,因此如果直接將byte賦值給int,當byte的符號位爲1時,int裏面的前24位會被賦值成1,因此出來的結果便不是你想要的。故將byte的值先與0x000000ff進行&操作,將前24位復位成0,結果便是正確。

 


public static final void StringToBytes(String in, byte[] b) throws Exception{
if (b.length < in.length() / 2) {
throw new Exception("byte array too small");
}
int j=0;
StringBuffer buf = new StringBuffer(2);
for (int i=0; i
buf.insert(0, in.charAt(i));
buf.insert(1, in.charAt(i+1));
int t = Integer.parseInt(buf.toString(),16);
b[j] = (byte)(t & (0xff));
i++;
buf.delete(0,2);
}
}

public static final String bytesToHexString(byte[] bArray) {
StringBuffer sb = new StringBuffer(bArray.length);
String sTemp;
for (int i = 0; i < bArray.length; i++) {
sTemp = Integer.toHexString((int)(0xFF & bArray[i]));
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}

 

總結:

流使用完需要close,一般情況下,儘量使用比如BufferedInputStream之類的buffer減少IO次數,提升性能。當然,BufferedInputStream會自動將字節轉換成字符,在協議解析程序裏面失去了意義。不過試用於字節流的Buffer也有許多,大家可以查找API。

 

參考資料:

http://xiaolongfeixiang.iteye.com/blog/648700

http://lavasoft.blog.51cto.com/62575/95387

http://java.sun.com/developer/technicalArticles/Streams/ProgIOStreams/

http://www.cnblogs.com/lich/archive/2011/12/11/2283700.html

發佈了76 篇原創文章 · 獲贊 4 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章