java io系列14之 DataInputStream数据输入流的认知源码和示例Word文档格式.docx
《java io系列14之 DataInputStream数据输入流的认知源码和示例Word文档格式.docx》由会员分享,可在线阅读,更多相关《java io系列14之 DataInputStream数据输入流的认知源码和示例Word文档格式.docx(32页珍藏版)》请在冰点文库上搜索。
![java io系列14之 DataInputStream数据输入流的认知源码和示例Word文档格式.docx](https://file1.bingdoc.com/fileroot1/2023-5/5/90c2a01b-87af-445e-be78-fece915756f3/90c2a01b-87af-445e-be78-fece915756f31.gif)
”
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<
utflen){
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<
utflen){
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]&
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>
84thrownewUTFDataFormatException(
85"
86char2=(int)bytearr[count-2];
87char3=(int)bytearr[count-1];
88if(((char2&
=0x80)||((char3&
=0x80))
89thrownewUTFDataFormatException(
90"
+(count-1));
91chararr[chararr_count++]=(char)(((c&
0x0F)<
12)|
92((char2&
0x3F)<
93((char3&
0));
94break;
95
96//若UTF-8是四字节,即bytearr[count]对应是“11110xxx10xxxxxx10xxxxxx10xxxxxx”形式中的第一个,即“11110xxx”
97//则bytearr[count]对应的int类型的c的取值是15
98default:
99/*10xxxxxx,1111xxxx*/
100thrownewUTFDataFormatException(
101"
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="
设置字符数组chararr="
否则的话,新建数组bytearr和chararr。
第3步,将UTF-8数据全部读取到“字节数组bytearr”中。
in.readFully(bytearr,0,utflen);
注意:
这里是存储到字节数组,而不是字符数组!
第4步,对UTF-8中的单字节数据进行预处理。
1while(count<
2//将每个字节转换成int值
3c=(int)bytearr[count]&
4//UTF-8的单字节数据的值都不会超过127;
5if(c>
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]&
switch(c>
//若UTF-8是单字节,即bytearr[count]对应是“0xxxxxxx”形式;
//则bytearr[count]对应的int类型的c的取值范围是0-7。
case0:
/*0xxxxxxx*/
count++;
chararr[chararr_count++]=(char)c;
break;
//若UTF-8是双字节,即bytearr[count]对应是“110xxxxx10xxxxxx”形式中的第一个,即“110xxxxx”
//则bytearr[count]对应的int类型的c的取值范围是12-13。
case12:
/*110xxxxx10xxxxxx*/
count+=2;
if(count>
thrownewUTFDataFormatException(
"
char2=(int)bytearr[count-1];
if((char2&
chararr[chararr_count++]=(char)(((c&
(char2&
//若UTF-8是三字节,即bytearr[count]对应是“1110xxxx10xxxxxx10xxxxxx”形式中的第一个,即“1110xxxx”
//则bytearr[count]对应的int类型的c的取值是14。
case14:
/*1110xxxx10xxxxxx10xxxxxx*/
count+=3;
char2=(int)bytearr[count-2];
char3=(int)bytearr[count-1];
if(((char2&
((char2&
((char3&
//若UTF-8是四字节,即bytearr[count]对应是“11110xxx10xxxxxx10xxxxxx10xxxxxx”形式中的第一个,即“11110xxx”
//则bytearr[count]对应的int类型的c的取值是15
default:
/*10xxxxxx,1111xxxx*/
}
}
(a)我们将下面的两条语句一起进行说明
c=(int)bytearr[count]&
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]&
和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]&
时,首先将bytearr[count]转换成int。
“110xxxxx”
转成int类型之后,变成
“111111111111111111111111110xxxxx”
因为“110xxxxx”是负数(第1为是1),所以转换成int类型时多出来的位补1。
(a.2)接着c=(int)bytearr[count]&
中,会将“转换成int类型后的bytearr[count]”与“0xff”进行逻辑与(即&
)操作。
结果如下:
“000000000000000000000000110xxxxx”
(a.3)执行c>
4时,会将上面的结果左移4位。
得到的结果如下:
“0000000000000000000000000000110x”
(b)上面的理解之后,swicth(c>
4){...}其中的省略号部分就相当容易理解了。
我们还是以“2字节UTF-8的通用格式”来说明。
它会执行case12和case13;
源码如下:
count+=2;
if(count>
char2=(int)bytearr[count-1];
if((char2&
chararr[chararr_count++]=(char)(((c&
6)|(char2&
(b.1)由于这种情况对应的UTF-8数据是“2字节”的,因此,执行count+2;
直接跳