DataInputStream 介绍
DataInputStream 是数据输入流。它继承于FilterInputStream。
DataInputStream 是用来装饰其它输入流,它“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型”。应用程序可以使用DataOutputStream(数据输出流)写入由DataInputStream(数据输入流)读取的数据。
DataInputStream 函数列表
DataInputStream(InputStream in)final int read(byte[] buffer, int offset, int length)final int read(byte[] buffer)final boolean readBoolean()final byte readByte()final char readChar()final double readDouble()final float readFloat()final void readFully(byte[] dst)final void readFully(byte[] dst, int offset, int byteCount)final int readInt()final String readLine()final long readLong()final short readShort()final static String readUTF(DataInput in)final String readUTF()final int readUnsignedByte()final int readUnsignedShort()final int skipBytes(int count)
DataInputStream.java源码分析(基于jdk1.7.40)
package java.io; public class DataInputStream extends FilterInputStream implements DataInput { // 构造函数。 public DataInputStream(InputStream in) { super(in); } private byte bytearr[] = new byte[80]; private char chararr[] = new char[80]; // 从“数据输入流”中读取一个字节 public final int read(byte b[]) throws IOException { return in.read(b, 0, b.length); } // 从“数据输入流”中读取数据并存储到字节数组b中。 // off是字节数组b中开始存储元素的起始位置。 // len是读取字节的个数。 public final int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } // 从“数据输入流”中读取数据并填满字节数组b中;没有填满数组b则一直读取,直到填满位置。 // 从字节数组b的位置0开始存储,并且读取的字节个数等于b的长度。 public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } // 从“数据输入流”中读取数据并存储到字节数组b中;若没读取len个字节,直到一直读取直到读取完len个字节为止。 public final void readFully(byte b[], int off, int len) throws IOException { if (len < 0) throw new IndexOutOfBoundsException(); int n = 0; while (n < len) { int count = in.read(b, off + n, len - n); if (count < 0) throw new EOFException(); n += count; } } // 跳过n个字节 public final int skipBytes(int n) throws IOException { int total = 0; int cur = 0; while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) { total += cur; } return total; } // 从“数据输入流”中读取boolean类型的值 public final boolean readBoolean() throws IOException { int ch = in.read(); if (ch < 0) throw new EOFException(); return (ch != 0); } // 从“数据输入流”中读取Byte类型的值 public final byte readByte() throws IOException { int ch = in.read(); if (ch < 0) throw new EOFException(); return (byte)(ch); } // 从“数据输入流”中读取“无符号的Byte类型”的值,即读取值为正数的byte值 public final int readUnsignedByte() throws IOException { int ch = in.read(); if (ch < 0) throw new EOFException(); return ch; } // 从“数据输入流”中读取“short类型”的值 public final short readShort() throws IOException { int ch = in.read(); int ch = in.read(); if ((ch1 | ch2) < 0) throw new EOFException(); return (short)((ch1 << 8) + (ch2 << 0)); } // 从“数据输入流”中读取“无符号的short类型”的值 public final int readUnsignedShort() throws IOException { int ch1 = in.read(); int ch2 = in.read(); if ((ch1 | ch2) < 0) throw new EOFException(); return (ch1 << 8) + (ch2 << 0); } // 从“数据输入流”中读取“char类型”的值 public final char readChar() throws IOException { int ch1 = in.read(); int ch2 = in.read(); if ((ch1 | ch2) < 0) throw new EOFException(); return (char)((ch1 << 8) + (ch2 << 0)); } // 从“数据输入流”中读取“int类型”的值 public final int readInt() throws IOException { int ch1 = in.read(); int ch2 = in.read(); int ch3 = in.read(); int ch4 = in.read(); if ((ch1 | ch2 | ch3 | ch4) < 0) throw new EOFException(); return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0)); } private byte readBuffer[] = new byte[8]; // 从“数据输入流”中读取“long类型”的值 public final long readLong() throws IOException { readFully(readBuffer, 0, 8); return (((long)readBuffer[0] << 56) + ((long)(readBuffer[1] & 255) << 48) + ((long)(readBuffer[2] & 255) << 40) + ((long)(readBuffer[3] & 255) << 32) + ((long)(readBuffer[4] & 255) << 24) + ((readBuffer[5] & 255) << 16) + ((readBuffer[6] & 255) << 8) + ((readBuffer[7] & 255) << 0)); } // 从“数据输入流”中读取“float类型”的值 public final float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } // 从“数据输入流”中读取“double类型”的值 public final double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } private char lineBuffer[]; @Deprecated public final String readLine() throws IOException { char buf[] = lineBuffer; if (buf == null) { buf = lineBuffer = new char[]; } int room = buf.length; int offset = 0; int c; loop: while (true) { switch (c = in.read()) { case -1: case '/n': break loop; case '/r': int c2 = in.read(); if ((c2 != '/n') && (c2 != -1)) { if (!(in instanceof PushbackInputStream)) { this.in = new PushbackInputStream(in); } ((PushbackInputStream)in).unread(c2); } break loop; default: if (--room < 0) { buf = new char[offset + 128]; room = buf.length - offset - 1; System.arraycopy(lineBuffer, 0, buf, 0, offset); lineBuffer = buf; } buf[offset++] = (char) c; break; } } if ((c == -1) && (offset == 0)) { return null; } return String.copyValueOf(buf, , offset); } // 从“数据输入流”中读取“UTF类型”的值 public final String readUTF() throws IOException { return readUTF(this); } public final static String readUTF(DataInput in) throws IOException { // 从“数据输入流”中读取“无符号的short类型”的值: // 注意:UTF-8输入流的前2个字节是数据的长度 int utflen = in.readUnsignedShort(); byte[] bytearr = null; char[] chararr = null; // 如果in本身是“数据输入流”, // 则,设置字节数组bytearr = "数据输入流"的成员bytearr // 设置字符数组chararr = "数据输入流"的成员chararr // 否则的话,新建数组bytearr和chararr 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; // 从“数据输入流”中读取数据并存储到字节数组bytearr中;从bytearr的位置0开始存储,存储长度为utflen。 // 注意,这里是存储到字节数组!而且读取的是全部的数据。 in.readFully(bytearr, 0, utflen); // 将“字节数组bytearr”中的数据 拷贝到 “字符数组chararr”中 // 注意:这里相当于“预处理的输入流中单字节的符号”,因为UTF-8是1-4个字节可变的。 while (count < utflen) { // 将每个字节转换成int值 c = (int) bytearr[count] & xff; // UTF-8的单字节数据的值都不会超过127;所以,超过127,则退出。 if (c > 127) break; count++; // 将c保存到“字符数组chararr”中 chararr[chararr_count++]=(char)c; } // 处理完输入流中单字节的符号之后,接下来我们继续处理。 while (count < utflen) { // 下面语句执行了2步操作。 // (01) 将字节由 “byte类型” 转换成 “int类型”。 // 例如, “11001010” 转换成int之后,是 “00000000 00000000 00000000 11001010” // (02) 将 “int类型” 的数据左移4位 // 例如, “00000000 00000000 00000000 11001010” 左移4位之后,变成 “00000000 00000000 00000000 00001100” c = (int) bytearr[count] & 0xff; switch (c >> 4) { // 若 UTF-8 是单字节,即 bytearr[count] 对应是 “0xxxxxxx” 形式; // 则 bytearr[count] 对应的int类型的c的取值范围是 0-7。 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* 0xxxxxxx*/ count++; chararr[chararr_count++]=(char)c; break; // 若 UTF-8 是双字节,即 bytearr[count] 对应是 “110xxxxx 10xxxxxx” 形式中的第一个,即“110xxxxx” // 则 bytearr[count] 对应的int类型的c的取值范围是 12-13。 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; // 若 UTF-8 是三字节,即 bytearr[count] 对应是 “1110xxxx 10xxxxxx 10xxxxxx” 形式中的第一个,即“1110xxxx” // 则 bytearr[count] 对应的int类型的c的取值是14 。 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; // 若 UTF-8 是四字节,即 bytearr[count] 对应是 “11110xxx 10xxxxxx 10xxxxxx 10xxxxxx” 形式中的第一个,即“11110xxx” // 则 bytearr[count] 对应的int类型的c的取值是15 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); } }
说明:
DataInputStream 的作用就是“允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。应用程序可以使用数据输出流写入稍后由数据输入流读取的数据。”
DataInputStream 中比较难以理解的函数就只有 readUTF(DataInput in);下面,对这个函数进行详细的介绍,其它的函数请参考源码中的注释。
readUTF(DataInput in)源码如下:
public final static String readUTF(DataInput in) throws IOException { // 从“数据输入流”中读取“无符号的short类型”的值: // 注意:UTF-8输入流的前2个字节是数据的长度 int utflen = in.readUnsignedShort(); byte[] bytearr = null; char[] chararr = null; // 如果in本身是“数据输入流”, // 则,设置字节数组bytearr = "数据输入流"的成员bytearr // 设置字符数组chararr = "数据输入流"的成员chararr // 否则的话,新建数组bytearr和chararr if (in instanceof DataInputStream) { DataInputStream dis = (DataInputStream)in; if (dis.bytearr.length < utflen){ dis.bytearr = new byte[utflen*]; dis.chararr = new char[utflen*]; } 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; // 从“数据输入流”中读取数据并存储到字节数组bytearr中;从bytearr的位置开始存储,存储长度为utflen。 // 注意,这里是存储到字节数组!而且读取的是全部的数据。 in.readFully(bytearr, 0, utflen); // 将“字节数组bytearr”中的数据 拷贝到 “字符数组chararr”中 // 注意:这里相当于“预处理的输入流中单字节的符号”,因为UTF-是-个字节可变的。 while (count < utflen) { // 将每个字节转换成int值 c = (int) bytearr[count] & xff; // UTF-8的每个字节的值都不会超过127;所以,超过127,则退出。 if (c > 127) break; count++; // 将c保存到“字符数组chararr”中 chararr[chararr_count++]=(char)c; } // 处理完输入流中单字节的符号之后,接下来我们继续处理。 while (count < utflen) { // 下面语句执行了2步操作。 // () 将字节由 “byte类型” 转换成 “int类型”。 // 例如, “11001010” 转换成int之后,是 “00000000 00000000 00000000 11001010” // (02) 将 “int类型” 的数据左移4位 // 例如, “00000000 00000000 00000000 11001010” 左移4位之后,变成 “00000000 00000000 00000000 00001100” c = (int) bytearr[count] & 0xff; switch (c >> 4) { // 若 UTF-8 是单字节,即 bytearr[count] 对应是 “0xxxxxxx” 形式; // 则 bytearr[count] 对应的int类型的c的取值范围是 0-7。 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* xxxxxxx*/ count++; chararr[chararr_count++]=(char)c; break; // 若 UTF-8 是双字节,即 bytearr[count] 对应是 “110xxxxx 10xxxxxx” 形式中的第一个,即“110xxxxx” // 则 bytearr[count] 对应的int类型的c的取值范围是 12-13。 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; // 若 UTF-8 是三字节,即 bytearr[count] 对应是 “1110xxxx 10xxxxxx 10xxxxxx” 形式中的第一个,即“1110xxxx” // 则 bytearr[count] 对应的int类型的c的取值是14 。 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; // 若 UTF-8 是四字节,即 bytearr[count] 对应是 “11110xxx 10xxxxxx 10xxxxxx 10xxxxxx” 形式中的第一个,即“11110xxx” // 则 bytearr[count] 对应的int类型的c的取值是 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); }
说明:
(01) readUTF()的作用,是从输入流中读取UTF-8编码的数据,并以String字符串的形式返回。
(02) 知道了readUTF()的作用之后,下面开始介绍readUTF()的流程:
第1步,读取出输入流中的UTF-8数据的长度。代码如下:
int utflen = in.readUnsignedShort();
UTF-8数据的长度包含在它的前两个字节当中;我们通过readUnsignedShort()读取出前两个字节对应的正整数就是UTF-8数据的长度。
第2步,创建2个数组:字节数组bytearr 和 字符数组chararr。代码如下:
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]; }
首先,判断该输入流本身是不是DataInputStream,即数据输入流;若是的话,
则,设置字节数组bytearr = "数据输入流"的成员bytearr
设置字符数组chararr = "数据输入流"的成员chararr
否则的话,新建数组bytearr和chararr。
第3步,将UTF-8数据全部读取到“字节数组bytearr”中。代码如下:
in.readFully(bytearr, 0, utflen);
注意: 这里是存储到字节数组,而不是字符数组!而且读取的是全部的数据。
第4步,对UTF-8中的单字节数据进行预处理。代码如下:
while (count < utflen) { // 将每个字节转换成int值 c = (int) bytearr[count] & xff; // UTF-8的单字节数据的值都不会超过127;所以,超过127,则退出。 if (c > 127) break; count++; // 将c保存到“字符数组chararr”中 chararr[chararr_count++]=(char)c; }
UTF-8的数据是变长的,可以是1-4个字节;在readUTF()中,我们最终是将全部的UTF-8数据保存到“字符数组(而不是字节数组)”中,再将其转换为String字符串。
由于UTF-8的单字节和ASCII相同,所以这里就将它们进行预处理,直接保存到“字符数组chararr”中。对于其它的UTF-8数据,则在后面进行处理。
第5步,对“第4步 预处理”之后的数据,接着进行处理。代码如下:
// 处理完输入流中单字节的符号之后,接下来我们继续处理。while (count < utflen) { // 下面语句执行了2步操作。 // (01) 将字节由 “byte类型” 转换成 “int类型”。 // 例如, “11001010” 转换成int之后,是 “00000000 00000000 00000000 11001010” // (02) 将 “int类型” 的数据左移4位 // 例如, “00000000 00000000 00000000 11001010” 左移4位之后,变成 “00000000 00000000 00000000 00001100” c = (int) bytearr[count] & 0xff; switch (c >> 4) { // 若 UTF-8 是单字节,即 bytearr[count] 对应是 “0xxxxxxx” 形式; // 则 bytearr[count] 对应的int类型的c的取值范围是 0-7。 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: /* 0xxxxxxx*/ count++; chararr[chararr_count++]=(char)c; break; // 若 UTF-8 是双字节,即 bytearr[count] 对应是 “110xxxxx 10xxxxxx” 形式中的第一个,即“110xxxxx” // 则 bytearr[count] 对应的int类型的c的取值范围是 12-13。 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; // 若 UTF-8 是三字节,即 bytearr[count] 对应是 “1110xxxx 10xxxxxx 10xxxxxx” 形式中的第一个,即“1110xxxx” // 则 bytearr[count] 对应的int类型的c的取值是14 。 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; // 若 UTF-8 是四字节,即 bytearr[count] 对应是 “11110xxx 10xxxxxx 10xxxxxx 10xxxxxx” 形式中的第一个,即“11110xxx” // 则 bytearr[count] 对应的int类型的c的取值是15 default: /* 10xx xxxx, 1111 xxxx */ throw new UTFDataFormatException( "malformed input around byte " + 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的通用格式 | 110xxxxx 10xxxxxx
3字节 UTF-8的通用格式 | 1110xxxx 10xxxxxx 10xxxxxx
4字节 UTF-8的通用格式 | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
执行 c = (int) bytearr[count] & 0xff; 和 c>>4 这2项操作之后,上面的数据变成
--------------------+---------------------------------------------
1字节 UTF-8的变换后对应的int类型值 | 00000000 00000000 00000000 00000xxx (范围是0~7)
2字节 UTF-8的变换后对应的int类型值 | 00000000 00000000 00000000 0000110x (范围是12~13)
3字节 UTF-8的变换后对应的int类型值 | 00000000 00000000 00000000 00001110 (范围是14)
4字节 UTF-8的变换后对应的int类型值 | 00000000 00000000 00000000 00001111 (范围是15)
为什么会是这样呢?
我们以“2字节 UTF-8的通用格式”来说明。
它的通用格式是 “110xxxxx 10xxxxxx”,我们在操作时,只会操作第1个字节,即只会操作“110xxxxx”
(a.1) 在执行 c = (int) bytearr[count] & 0xff; 时,首先将 bytearr[count] 转换成int。
“110xxxxx”
转成int类型之后,变成
“11111111 11111111 11111111 110xxxxx”
因为“110xxxxx”是负数(第1为是1),所以转换成int类型时多出来的位补1。
(a.2) 接着 c = (int) bytearr[count] & 0xff; 中,会将 “转换成int类型后的bytearr[count]” 与 “0xff”进行 逻辑与(即&) 操作。结果如下:
“00000000 00000000 00000000 110xxxxx”
(a.3) 执行 c>>4 时,会将上面的结果左移4位。得到的结果如下:
“00000000 00000000 00000000 0000110x”
(b) 上面的理解之后,swicth (c>>4) { ... } 其中的省略号部分就相当容易理解了。
我们还是以“2字节 UTF-8的通用格式”来说明。
它会执行 case 12 和 case 13;源码如下:
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));
(b.1) 由于这种情况对应的UTF-8数据是“2字节”的,因此,执行count+2;直接跳过2个字节。
(b.2) 由于chararr的元素是字符类型,而一个字符正好占2个字节;因为正好将(((c & 0x1F) << 6) | (char2 & 0x3F)); 的结果转换成char,然后保存在chararr数组中。
第6步,将字符数组转换成String字符串,并返回。代码如下:
return new String(chararr, 0, chararr_count);
示例代码
关于DataInputStream中API的详细用法,参考示例代码(DataInputStreamTest.java):
import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStream; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.FileNotFoundException; import java.lang.SecurityException; /** * DataInputStream 和 DataOutputStream测试程序 * * */ public class DataInputStreamTest { private static final int LEN = 5; public static void main(String[] args) { // 测试DataOutputStream,将数据写入到输出流中。 testDataOutputStream() ; // 测试DataInputStream,从上面的输出流结果中读取数据。 testDataInputStream() ; } /** * DataOutputStream的API测试函数 */ private static void testDataOutputStream() { try { File file = new File("file.txt"); DataOutputStream out = new DataOutputStream( new FileOutputStream(file)); out.writeBoolean(true); out.writeByte((byte)0x41); out.writeChar((char)0x4243); out.writeShort((short)0x4445); out.writeInt(0x12345678); out.writeLong(0x0FEDCBA987654321L); out.writeUTF("abcdefghijklmnopqrstuvwxyz严12"); out.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * DataInputStream的API测试函数 */ private static void testDataInputStream() { try { File file = new File("file.txt"); DataInputStream in = new DataInputStream( new FileInputStream(file)); System.out.printf("byteToHexString(0x8F):0x%s/n", byteToHexString((byte)0x8F)); System.out.printf("charToHexString(0x8FCF):0x%s/n", charToHexString((char)0x8FCF)); System.out.printf("readBoolean():%s/n", in.readBoolean()); System.out.printf("readByte():0x%s/n", byteToHexString(in.readByte())); System.out.printf("readChar():0x%s/n", charToHexString(in.readChar())); System.out.printf("readShort():0x%s/n", shortToHexString(in.readShort())); System.out.printf("readInt():0x%s/n", Integer.toHexString(in.readInt())); System.out.printf("readLong():0x%s/n", Long.toHexString(in.readLong())); System.out.printf("readUTF():%s/n", in.readUTF()); in.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // 打印byte对应的16进制的字符串 private static String byteToHexString(byte val) { return Integer.toHexString(val & xff); } // 打印char对应的进制的字符串 private static String charToHexString(char val) { return Integer.toHexString(val); } // 打印short对应的16进制的字符串 private static String shortToHexString(short val) { return Integer.toHexString(val & xffff); } }
运行结果:
byteToHexString(0x8F):0x8fcharToHexString(0x8FCF):0x8fcfreadBoolean():truereadByte():0x41readChar():0x4243readShort():0x4445readInt():0x12345678readLong():0xfedcba987654321readUTF():abcdefghijklmnopqrstuvwxyz严12
结果说明:
(01) 查看file.txt文本。16进制的数据显示如下:
001f 对应的int值是31。它表示的含义是后面的UTF-8数据的长度。字符串“abcdefghijklmnopqrstuvwxyz严12”中字母“ab...xyz”的长度是26,“严”对应的UTF-8数据长度是3;“12”长度是2。总的长度=26+3+2=31。
(02) 返回byte对应的16进制的字符串
源码如下:
private static String byteToHexString(byte val) { return Integer.toHexString(val & 0xff);}
想想为什么代码是:
return Integer.toHexString(val & 0xff);
而不是
return Integer.toHexString(val);
我们先看看 byteToHexString((byte)0x8F); 在上面两种情况下的输出结果。
return Integer.toHexString(val & 0xff); 对应的输出是“0xffffff8f”return Integer.toHexString(val); 对应的输出是“0x8f”
为什么会这样呢?
原因其实很简单,就是“byte类型转换成int类型”导致的问题。
byte类型的0x8F是一个负数,它对应的2进制是10001111;将一个负数的byte转换成int类型时,执行的是有符号转型(新增位都填充符号位的数字)。0x8F的符号位是1,因为将它转换成int时,填充“1”;转型后的结果(2进制)是11111111 11111111 11111111 10001111,对应的16进制为0xffffff8f。
因为当我们执行Integer.toHexString(val);时,返回的就是0xffffff8f。
在Integer.toHexString(val & 0xff)中,相当于0xffffff8f & 0xff,得到的结果是0x8f。
(03) 返回char和short对应的16进制的字符串
“返回char对应的16进制的字符串”对应的源码如下:
private static String charToHexString(char val) { return Integer.toHexString(val);}
“返回short对应的16进制的字符串”对应源码如下:
private static String shortToHexString(short val) { return Integer.toHexString(val & 0xffff);}
比较上面的两个函数,为什么一个是 “val” ,而另一个是 “val & 0xffff”?
通过(02)的分析,我们类似的推出为什么 “返回short对应的16进制的字符串” 要执行“val & 0xffff”。
但是,为什么 “返回char对应的16进制的字符串” 要执行 “val” 即可。原因也很简单,java中char是无符号类型,占两个字节。将char转换为int类型,执行的是无符号转型,新增为都填充0。
以上所述是小编给大家介绍的Java 中的 DataInputStream的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对VeVb武林网网站的支持!
新闻热点
疑难解答
图片精选