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<in.length(); i++, j++) {
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





posted @ 2012-01-15 14:28  阿波zju  阅读(2434)  评论(2编辑  收藏  举报