java io系列14之 DataInputStream数据输入流的认知源码和示例.docx
- 文档编号:3275591
- 上传时间:2023-05-05
- 格式:DOCX
- 页数:32
- 大小:49.24KB
java io系列14之 DataInputStream数据输入流的认知源码和示例.docx
《java io系列14之 DataInputStream数据输入流的认知源码和示例.docx》由会员分享,可在线阅读,更多相关《java io系列14之 DataInputStream数据输入流的认知源码和示例.docx(32页珍藏版)》请在冰点文库上搜索。
javaio系列14之DataInputStream数据输入流的认知源码和示例
DataInputStream介绍
DataInputStream是数据输入流。
它继承于FilterInputStream。
DataInputStream是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型”。
应用程序可以使用DataOutputStream(数据输出流)写入由DataInputStream(数据输入流)读取的数据。
DataInputStream函数列表
DataInputStream(InputStreamin)
finalintread(byte[]buffer,intoffset,intlength)
finalintread(byte[]buffer)
finalbooleanreadBoolean()
finalbytereadByte()
finalcharreadChar()
finaldoublereadDouble()
finalfloatreadFloat()
finalvoidreadFully(byte[]dst)
finalvoidreadFully(byte[]dst,intoffset,intbyteCount)
finalintreadInt()
finalStringreadLine()
finallongreadLong()
finalshortreadShort()
finalstaticStringreadUTF(DataInputin)
finalStringreadUTF()
finalintreadUnsignedByte()
finalintreadUnsignedShort()
finalintskipBytes(intcount)
DataInputStream.java源码分析(基于jdk1.7.40)
ViewCode
说明:
DataInputStream的作用就是“允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型。
应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。
”
DataInputStream中比较难以理解的函数就只有readUTF(DataInputin);下面,对这个函数进行详细的介绍,其它的函数请参考源码中的注释。
readUTF(DataInputin)源码如下:
1publicfinalstaticStringreadUTF(DataInputin)throwsIOException{
2//从“数据输入流”中读取“无符号的short类型”的值:
3//注意:
UTF-8输入流的前2个字节是数据的长度
4intutflen=in.readUnsignedShort();
5byte[]bytearr=null;
6char[]chararr=null;
7
8//如果in本身是“数据输入流”,
9//则,设置字节数组bytearr="数据输入流"的成员bytearr
10//设置字符数组chararr="数据输入流"的成员chararr
11//否则的话,新建数组bytearr和chararr
12if(ininstanceofDataInputStream){
13DataInputStreamdis=(DataInputStream)in;
14if(dis.bytearr.length 15dis.bytearr=newbyte[utflen*2]; 16dis.chararr=newchar[utflen*2]; 17} 18chararr=dis.chararr; 19bytearr=dis.bytearr; 20}else{ 21bytearr=newbyte[utflen]; 22chararr=newchar[utflen]; 23} 24 25intc,char2,char3; 26intcount=0; 27intchararr_count=0; 28 29//从“数据输入流”中读取数据并存储到字节数组bytearr中;从bytearr的位置0开始存储,存储长度为utflen。 30//注意,这里是存储到字节数组! 而且读取的是全部的数据。 31in.readFully(bytearr,0,utflen); 32 33//将“字节数组bytearr”中的数据拷贝到“字符数组chararr”中 34//注意: 这里相当于“预处理的输入流中单字节的符号”,因为UTF-8是1-4个字节可变的。 35while(count 36//将每个字节转换成int值 37c=(int)bytearr[count]&0xff; 38//UTF-8的每个字节的值都不会超过127;所以,超过127,则退出。 39if(c>127)break; 40count++; 41//将c保存到“字符数组chararr”中 42chararr[chararr_count++]=(char)c; 43} 44 45//处理完输入流中单字节的符号之后,接下来我们继续处理。 46while(count 47//下面语句执行了2步操作。 48//(01)将字节由“byte类型”转换成“int类型”。 49//例如,“11001010”转换成int之后,是“00000000000000000000000011001010” 50//(02)将“int类型”的数据左移4位 51//例如,“00000000000000000000000011001010”左移4位之后,变成“00000000000000000000000000001100” 52c=(int)bytearr[count]&0xff; 53switch(c>>4){ 54//若UTF-8是单字节,即bytearr[count]对应是“0xxxxxxx”形式; 55//则bytearr[count]对应的int类型的c的取值范围是0-7。 56case0: case1: case2: case3: case4: case5: case6: case7: 57/*0xxxxxxx*/ 58count++; 59chararr[chararr_count++]=(char)c; 60break; 61 62//若UTF-8是双字节,即bytearr[count]对应是“110xxxxx10xxxxxx”形式中的第一个,即“110xxxxx” 63//则bytearr[count]对应的int类型的c的取值范围是12-13。 64case12: case13: 65/*110xxxxx10xxxxxx*/ 66count+=2; 67if(count>utflen) 68thrownewUTFDataFormatException( 69"malformedinput: partialcharacteratend"); 70char2=(int)bytearr[count-1]; 71if((char2&0xC0)! =0x80) 72thrownewUTFDataFormatException( 73"malformedinputaroundbyte"+count); 74chararr[chararr_count++]=(char)(((c&0x1F)<<6)| 75(char2&0x3F)); 76break; 77 78//若UTF-8是三字节,即bytearr[count]对应是“1110xxxx10xxxxxx10xxxxxx”形式中的第一个,即“1110xxxx” 79//则bytearr[count]对应的int类型的c的取值是14。 80case14: 81/*1110xxxx10xxxxxx10xxxxxx*/ 82count+=3; 83if(count>utflen) 84thrownewUTFDataFormatException( 85"malformedinput: partialcharacteratend"); 86char2=(int)bytearr[count-2]; 87char3=(int)bytearr[count-1]; 88if(((char2&0xC0)! =0x80)||((char3&0xC0)! =0x80)) 89thrownewUTFDataFormatException( 90"malformedinputaroundbyte"+(count-1)); 91chararr[chararr_count++]=(char)(((c&0x0F)<<12)| 92((char2&0x3F)<<6)| 93((char3&0x3F)<<0)); 94break; 95 96//若UTF-8是四字节,即bytearr[count]对应是“11110xxx10xxxxxx10xxxxxx10xxxxxx”形式中的第一个,即“11110xxx” 97//则bytearr[count]对应的int类型的c的取值是15 98default: 99/*10xxxxxx,1111xxxx*/ 100thrownewUTFDataFormatException( 101"malformedinputaroundbyte"+count); 102} 103} 104//Thenumberofcharsproducedmaybelessthanutflen 105returnnewString(chararr,0,chararr_count); 106} 说明: (01)readUTF()的作用,是从输入流中读取UTF-8编码的数据,并以String字符串的形式返回。 (02)知道了readUTF()的作用之后,下面开始介绍readUTF()的流程: 第1步,读取出输入流中的UTF-8数据的长度。 代码如下: intutflen=in.readUnsignedShort(); UTF-8数据的长度包含在它的前两个字节当中;我们通过readUnsignedShort()读取出前两个字节对应的正整数就是UTF-8数据的长度。 第2步,创建2个数组: 字节数组bytearr和字符数组chararr。 代码如下: 1if(ininstanceofDataInputStream){ 2DataInputStreamdis=(DataInputStream)in; 3if(dis.bytearr.length 4dis.bytearr=newbyte[utflen*2]; 5dis.chararr=newchar[utflen*2]; 6} 7chararr=dis.chararr; 8bytearr=dis.bytearr; 9}else{ 10bytearr=newbyte[utflen]; 11chararr=newchar[utflen]; 12} 首先,判断该输入流本身是不是DataInputStream,即数据输入流;若是的话, 则,设置字节数组bytearr="数据输入流"的成员bytearr 设置字符数组chararr="数据输入流"的成员chararr 否则的话,新建数组bytearr和chararr。 第3步,将UTF-8数据全部读取到“字节数组bytearr”中。 代码如下: in.readFully(bytearr,0,utflen); 注意: 这里是存储到字节数组,而不是字符数组! 而且读取的是全部的数据。 第4步,对UTF-8中的单字节数据进行预处理。 代码如下: 1while(count 2//将每个字节转换成int值 3c=(int)bytearr[count]&0xff; 4//UTF-8的单字节数据的值都不会超过127;所以,超过127,则退出。 5if(c>127)break; 6count++; 7//将c保存到“字符数组chararr”中 8chararr[chararr_count++]=(char)c; 9} UTF-8的数据是变长的,可以是1-4个字节;在readUTF()中,我们最终是将全部的UTF-8数据保存到“字符数组(而不是字节数组)”中,再将其转换为String字符串。 由于UTF-8的单字节和ASCII相同,所以这里就将它们进行预处理,直接保存到“字符数组chararr”中。 对于其它的UTF-8数据,则在后面进行处理。 第5步,对“第4步预处理”之后的数据,接着进行处理。 代码如下: //处理完输入流中单字节的符号之后,接下来我们继续处理。 while(count //下面语句执行了2步操作。 //(01)将字节由“byte类型”转换成“int类型”。 //例如,“11001010”转换成int之后,是“00000000000000000000000011001010” //(02)将“int类型”的数据左移4位 //例如,“00000000000000000000000011001010”左移4位之后,变成“00000000000000000000000000001100” c=(int)bytearr[count]&0xff; switch(c>>4){ //若UTF-8是单字节,即bytearr[count]对应是“0xxxxxxx”形式; //则bytearr[count]对应的int类型的c的取值范围是0-7。 case0: case1: case2: case3: case4: case5: case6: case7: /*0xxxxxxx*/ count++; chararr[chararr_count++]=(char)c; break; //若UTF-8是双字节,即bytearr[count]对应是“110xxxxx10xxxxxx”形式中的第一个,即“110xxxxx” //则bytearr[count]对应的int类型的c的取值范围是12-13。 case12: case13: /*110xxxxx10xxxxxx*/ count+=2; if(count>utflen) thrownewUTFDataFormatException( "malformedinput: partialcharacteratend"); char2=(int)bytearr[count-1]; if((char2&0xC0)! =0x80) thrownewUTFDataFormatException( "malformedinputaroundbyte"+count); chararr[chararr_count++]=(char)(((c&0x1F)<<6)| (char2&0x3F)); break; //若UTF-8是三字节,即bytearr[count]对应是“1110xxxx10xxxxxx10xxxxxx”形式中的第一个,即“1110xxxx” //则bytearr[count]对应的int类型的c的取值是14。 case14: /*1110xxxx10xxxxxx10xxxxxx*/ count+=3; if(count>utflen) thrownewUTFDataFormatException( "malformedinput: partialcharacteratend"); char2=(int)bytearr[count-2]; char3=(int)bytearr[count-1]; if(((char2&0xC0)! =0x80)||((char3&0xC0)! =0x80)) thrownewUTFDataFormatException( "malformedinputaroundbyte"+(count-1)); chararr[chararr_count++]=(char)(((c&0x0F)<<12)| ((char2&0x3F)<<6)| ((char3&0x3F)<<0)); break; //若UTF-8是四字节,即bytearr[count]对应是“11110xxx10xxxxxx10xxxxxx10xxxxxx”形式中的第一个,即“11110xxx” //则bytearr[count]对应的int类型的c的取值是15 default: /*10xxxxxx,1111xxxx*/ thrownewUTFDataFormatException( "malformedinputaroundbyte"+count); } } (a)我们将下面的两条语句一起进行说明 c=(int)bytearr[count]&0xff; switch(c>>4){...} 首先,我们必须要理解为什么要这么做(执行上面2条语句)呢? 原因很简单,这么做的目的就是为了区分UTF-8数据是几位的;因为UTF-8的数据是1~4字节不等。 我们先看看UTF-8在1~4位情况下的格式。 --------------------+--------------------------------------------- 1字节UTF-8的通用格式|0xxxxxxx 2字节UTF-8的通用格式|110xxxxx10xxxxxx 3字节UTF-8的通用格式|1110xxxx10xxxxxx10xxxxxx 4字节UTF-8的通用格式|11110xxx10xxxxxx10xxxxxx10xxxxxx 执行c=(int)bytearr[count]&0xff;和c>>4这2项操作之后,上面的数据变成 --------------------+--------------------------------------------- 1字节UTF-8的变换后对应的int类型值|00000000000000000000000000000xxx(范围是0~7) 2字节UTF-8的变换后对应的int类型值|0000000000000000000000000000110x(范围是12~13) 3字节UTF-8的变换后对应的int类型值|00000000000000000000000000001110(范围是14) 4字节UTF-8的变换后对应的int类型值|00000000000000000000000000001111(范围是15) 为什么会是这样呢? 我们以“2字节UTF-8的通用格式”来说明。 它的通用格式是“110xxxxx10xxxxxx”,我们在操作时,只会操作第1个字节,即只会操作“110xxxxx” (a.1)在执行c=(int)bytearr[count]&0xff;时,首先将bytearr[count]转换成int。 “110xxxxx” 转成int类型之后,变成 “111111111111111111111111110xxxxx” 因为“110xxxxx”是负数(第1为是1),所以转换成int类型时多出来的位补1。 (a.2)接着c=(int)bytearr[count]&0xff;中,会将“转换成int类型后的bytearr[count]”与“0xff”进行逻辑与(即&)操作。 结果如下: “000000000000000000000000110xxxxx” (a.3)执行c>>4时,会将上面的结果左移4位。 得到的结果如下: “0000000000000000000000000000110x” (b)上面的理解之后,swicth(c>>4){...}其中的省略号部分就相当容易理解了。 我们还是以“2字节UTF-8的通用格式”来说明。 它会执行case12和case13;源码如下: count+=2; if(count>utflen) thrownewUTFDataFormatException( "malformedinput: partialcharacteratend"); char2=(int)bytearr[count-1]; if((char2&0xC0)! =0x80) thrownewUTFDataFormatException( "malformedinputaroundbyte"+count); chararr[chararr_count++]=(char)(((c&0x1F)<<6)|(char2&0x3F)); (b.1)由于这种情况对应的UTF-8数据是“2字节”的,因此,执行count+2;直接跳
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java io系列14之 DataInputStream数据输入流的认知源码和示例 io 系列 14 DataInputStream 数据 输入 认知 源码 示例