readUTF()源码解析

readUTF()源码解析

 

在学习张宏老师的《自己动手写Java虚拟机时》,发现了一个问题

所以,就以此为契机,查看一下源码;

ctrl+B再进去一下:

 

1.完整源码

源码如下:

public final static String readUTF(DataInput in) throws IOException {
    int utflen = in.readUnsignedShort();
    byte[] bytearr = null;
    char[] chararr = null;
    if (in instanceof DataInputStream) {
        DataInputStream dis = (DataInputStream)in;
        if (dis.bytearr.length < utflen){
            dis.bytearr = new byte[utflen*2];
            dis.chararr = new char[utflen*2];
        }
        chararr = dis.chararr;
        bytearr = dis.bytearr;
    } else {
        bytearr = new byte[utflen];
        chararr = new char[utflen];
    }

    int c, char2, char3;
    int count = 0;
    int chararr_count=0;

    in.readFully(bytearr, 0, utflen);

    while (count < utflen) {
        c = (int) bytearr[count] & 0xff;
        if (c > 127) break;
        count++;
        chararr[chararr_count++]=(char)c;
    }

    while (count < utflen) {
        c = (int) bytearr[count] & 0xff;
        switch (c >> 4) {
            case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
                /* 0xxxxxxx*/
                count++;
                chararr[chararr_count++]=(char)c;
                break;
            case 12: case 13:
                /* 110x xxxx 10xx xxxx*/
                count += 2;
                if (count > utflen)
                    throw new UTFDataFormatException(
                        "malformed input: partial character at end");
                char2 = (int) bytearr[count-1];
                if ((char2 & 0xC0) != 0x80)
                    throw new UTFDataFormatException(
                        "malformed input around byte " + count);
                chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |
                (char2 & 0x3F));
                break;
            case 14:
                /* 1110 xxxx 10xx xxxx 10xx xxxx */
                count += 3;
                if (count > utflen)
                    throw new UTFDataFormatException(
                        "malformed input: partial character at end");
                char2 = (int) bytearr[count-2];
                char3 = (int) bytearr[count-1];
                if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))
                    throw new UTFDataFormatException(
                        "malformed input around byte " + (count-1));
                chararr[chararr_count++]=(char)(((c & 0x0F) << 12) |
                ((char2 & 0x3F) << 6) |
                ((char3 & 0x3F) << 0));
                break;
            default:
                /* 10xx xxxx, 1111 xxxx */
                throw new UTFDataFormatException(
                    "malformed input around byte " + count);
            }
        }
        // The number of chars produced may be less than utflen
        return new String(chararr, 0, chararr_count);
    }
}

 

 

 

2.源码解释

readUTF的一般作用是它将Unicode字符串读取为modified UTF-8并作为字符串返回。

 

解释:

readUTF的作用是它读取以modified UTF-8格式编码的Unicode字符串的表示,然后作为字符串返回。

1.第一步

首先传入一个DataInput

DataInput接口提供了从二进制流中读取字节并从中重构任何Java基本类型中的数据的功能。

 

2.第二步

调用DataInput接口的readUnsignedShort()方法

其实,就是调用实现了DataInput接口的DataInputStream的readUnsignedShort()方法

这个方法的具体实现为

 

read方法:从这个输入流中读取下一个字节的数据。返回值byte为int型,取值范围为0到255。如果由于到达流的末尾而没有可用的字节,则返回值-1。此方法阻塞,直到输入数据可用、检测到流的末尾或抛出异常为止。这个方法只是执行in.read()并返回结果。

用read方法读取一个字节返回这个字节的Unicode编码,再用read方法读取下一个字节返回这个字节的Unicode编码,当读取一个字节的数据,到达流的末尾而没有可用的字节,则返回值-1。此时ch1和ch2才或运算小于零,而抛出EOFException。

否则返回ch1左移8位和ch2左移0位之和,

 

比如,第一个字符为s,第二个字符为f

s的Unicode编码为115,二进制是01110011

左移8位为0111001100000000

 

f的Unicode编码为115,二进制是01100110,左移0位不变

 

s左移8位和f左移0位之和,就是0111001101100110,也就是29542

如图:

也就是让其变为两个字节存储的二进制字符。读取两个字节,并按照readUnsignedShort方法的方式构造一个无符号16位整数。

 

3.第三步

将这些字节转换为字符:

分四种情况:

3.1.0xxxxxxx

  • 如果组的第一个字节匹配位模式0xxxxxxx(其中x表示“可能是0或1”),则该组仅由该字节组成。字节被零扩展以形成一个字符。

直接break,最后返回new String(chararr, 0, chararr_count),方法结束。

 

3.2.110xxxxx

  • 如果组的第一个字节匹配位模式110xxxxx,则该组由字节a和第二个字节b组成。如果没有字节b(因为字节a是要读取的最后一个字节),或者如果字节b不匹配位模式10xxxxxx,则抛出UTFDataFormatException。

否则,组将转换为字符(对于a,只要110后面5个位就行,二进制11111转换十进制是31,也就是与0x1F就行。b同理,与0x3F就行):

 

 

3.3.1110xxxx

  • 如果组的第一个字节匹配位模式1110xxxx,则该组由字节a和另外两个字节b和c组成。如果没有字节c(因为字节a是要读取的最后两个字节之一),或者字节b或字节c不匹配位模式10xxxxxx,则抛出UTFDataFormatException。否则,组将转换为字符:

 

 

3.4.1111xxxx或模式10xxxxxx匹配

  • 如果组的第一个字节与模式1111xxxx或模式10xxxxxx匹配,则抛出一个UTFDataFormatException。

 

 

而如果在整个过程中任何时候遇到文件结束,则抛出EOFException。

在通过这个过程将每个组转换为字符之后,将按照从输入流读取相应组的相同顺序收集字符,以形成一个字符串,并返回该字符串。

 

 

DataOutput接口的writeUTF方法可用于写入适合该方法读取的数据。

下次再讲吧

 

参考:

官方解释;DataInput (Java Platform SE 8 ) (oracle.com)

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇