DataInputStream为数据输入流,它允许应用程序以与机器无关方式从底层输入流中读取基本Java数据类型。
DataOutputStream为数据输出流,它允许应用程序以适当方式将基本 Java数据类型写入输出流中。
阅读源码需要复习一些基础知识,比如基本数据类型、位移运算、&xFF操作。
先来复习下基本数据类型各有多少位。
再来复习下位移运算符中的<<和>>>。
<<表示左移运算符,是将运算符左边的对象,向左移动运算符右边指定的位数,并且在低位补零。其实,向左移n 位,就相当于乘上2 的n 次方。
如,20 < 2;20的二进制为 0001 0100,右移2位后为 0010 1000,则结果就为 40;
>>>表示无符号右移,也叫逻辑右移。即若该数为正,则高位补0,而若该数为负数,则右移后高位同样补0。
如,20 >>> 2;20的二进制为 0001 0100,右移2位后为 0000 0101,则结果就为 5;
而-20 >> 2;-20的二进制为 1110 1011,右移2位,此时高位补0,即 0011 1010,结果为58;
最后复习下&xFF操作代表什么含义。
取低8位。0xFF是二进制的 1111 1111,那么0000 1010 0101 0101&1111 1111就能取到0000 1010 0101 0101的低8位。
DataInputStream下面来看下DataInputStream的源码。
/** * DataInput接口用于从二进制流中读取字节,并根据所有Java基本类型数据进行重构。 * 同时还提供根据UTF-8修改版格式的数据重构String的工具。 */public class DataInputStream extends FilterInputStream implements DataInput { /** * 构造方法之一 * 使用特定的输出流创建DataInputStream */ public DataInputStream(InputStream in) { super(in); } /** * readUTF()使用的数组 */ private byte bytearr[] = new byte[80]; private char chararr[] = new char[80]; /** * 从输入流中读取b.length个数据保存到byte数组b中。 * 实际读取的字节数以整数的形式返回。 * 在输入数据可用、检测到文件末尾、或抛出异常之前,该方法一直阻塞。 * 如果b为null,会抛出NullPointerException。 * 如果b长度为0,不会读取数据,方法返回值为0;否则会尝试读取至少一个字节。 * 如果因为流在文件末尾导致没有字节可用,将返回-1;否则至少会读取一个字节并保存到b中。 * * 第一个字节保存到b[0],下一个字节保存到b[1],以此类推。 * 读取的字节数最大等于b的长度。 * * 此方法等价于read(b, 0, b.length) * * @param b 存储读取数据的byte数组 * @return 实际读取的字节数, 如果因为到达流末尾导致没有数据,返回-1。 * @exception IOException 如果不是因为流位于文件末尾而无法读取第一个字节;该流已关闭并且底层输入流在关闭后不支持读取操作;发生其他 I/O错误。 */ public final int read(byte b[]) throws IOException { return in.read(b, 0, b.length); } /** * 从包含的输入流中将最多len个字节读入一个byte数组中。 * 尽量读取len个字节,但读取的字节数可能少于len个,也可能为零。 * 以整数形式返回实际读取的字节数。 * 在输入数据可用、检测到文件末尾或抛出异常之前,此方法将阻塞。 * * 如果len为零,则不读取任何字节并返回0; * 否则,尝试读取至少一个字节。如果因为流位于文件未尾而没有字节可用,则返回值-1; * 否则,至少读取一个字节并将其存储到b中。 * * @param b 存储读取数据的缓冲区。 * @param off 目标数组 b 中的起始偏移量 * @param len 读取的最大字节数。 * @return 读入缓冲区的字节总数;如果因为已经到达流末尾而没有更多的数据,则返回-1。 * @exception NullPointerException 如果b为null。 * @exception IndexOutOfBoundsException 如果off为负, len为负,或者len大于b.length-off * @exception IOException 如果不是因为流位于文件末尾而无法读取第一个字节;该流已关闭并且底层输入流在关闭后不支持读取操作;发生其他I/O */ public final int read(byte b[], int off, int len) throws IOException { return in.read(b, off, len); } /** * 参考DataInput.readFully()的介绍。 * * 以下是DataInput.readFully()的介绍。 * 从输入流中读取一些字节,并将它们存储在缓冲区数组b中。读取的字节数等于b的长度。 * * 该方法的执行结果有三种: * 1.输入数据的 len 个字节是可用的,在这种情况下,正常返回。 * 2.检测到文件末尾,在这种情况下,抛出 EOFException。 * 3.如果发生 I/O 错误,在这种情况下,将抛出 IOException,而不是 EOFException。 * * 如果b为null,则抛出NullPointerException。 * 如果off为负,或len为负,或者off+len大于数组b的长度,则抛出IndexOutOfBoundsException。 * 如果len为零,则不读取字节。 * 否则,将读取的第一个字节存储到元素b[off]中,下一个字节存储到 b[off+1]中, * 依此类推。读取的字节数至多等于b[0]。 * * @param b 存储读取数据的缓冲区。 * @exception EOFException 如果此输入流在读取所有字节之前到达末尾。 * @exception IOException 该流已关闭并且包含的输入流在关闭后不支持读取操作,或者发生其他 I/O 错误。 */ public final void readFully(byte b[]) throws IOException { readFully(b, 0, b.length); } /** * 参考readFully(byte b[]) * * @param b 存储读取数据的缓冲区。 * @param off 指定数据中的偏移量 * @param len 指定读取的字节数 * @exception EOFException 如果此流在读取所有字节之前到达末尾。 * @exception IOException 该流已关闭并且包含的输入流在关闭后不支持读取操作,或者发生其他I/O错误。 */ public final void readFully(byte b[], int off, int len) throws IOException { //如果参数不合法,抛出异常 if (len < 0) throw new IndexOutOfBoundsException(); int n = 0; //读取字节,直到读取了len个字节 while (n < len) { int count = in.read(b, off + n, len - n); //如果此流在读取所有字节之前到达末尾,抛出异常 if (count < 0) throw new EOFException(); n += count; } } /** * 参考DataInput.skipBytes()的介绍。 * * 以下是DataInput.skipBytes()的介绍: * 试图在输入流中跳过数据的n个字节,并丢弃跳过的字节。 * 不过,可以跳过更少的字节数,该字节数甚至可以为零。 * 这可能由很多情况引起;在已经跳过n个字节前到达文件末尾只是其中的一种可能。此方法从不抛出EOFException。返回实际跳过的字节数。 * * @param n 要跳过的字节数 * @return 实际跳过的字节数。 * @exception IOException 如果包含的输入流不支持查找操作;该流已关闭并且包含的输入流在关闭后不支持读取操作;发生其他I/O错误。 */ public final int skipBytes(int n) throws IOException { //实际跳过的字节数 int total = 0; //每次跳过的字节数 int cur = 0; //如果还没有跳过n个字节,且还没有到达文件末尾,就继续向下跳 while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) { //累加每次跳过的字节数 total += cur; } //返回实际跳过的字节数 return total; } /** * 参考DataInput.readBoolean() * * 以下是DataInput.readBoolean()的介绍: * * 从输入流中读取一个输入字节,如果该字节不是零,则返回true; * 如果是零,则返回false。此方法适用于读取用接口DataOutput的 writeBoolean方法写入的字节。 * * @return 如果读取的字节不是零,则返回true;如果是零,则返回false * @exception EOFException 如果此输入流已经到达末尾。 * @exception IOException 该流已关闭并且包含的输入流在关闭后不支持读取操作,或者发生另其他I/O错误。 */ public final boolean readBoolean() throws IOException { //从输入流中读取一个字节 int ch = in.read(); //如果达到输入流末尾,抛出异常 if (ch < 0) throw new EOFException(); //如果读取的字节不是零,则返回true;如果是零,则返回false return (ch != 0); } /** * 参考DataInput.readByte方法的介绍。 * * 以下是DataInput.readByte方法的介绍: * * 从输入流中读取并返回一个输入字节。 */ public final byte readByte() throws IOException { int ch = in.read(); if (ch < 0) throw new EOFException(); return (byte)(ch); } /** * 参考DataInput.readUnsignedByte方法的介绍 * * 下面是DataInput.readUnsignedByte方法的介绍: * * 读取一个输入字节,将它左侧补零转变为int类型,并返回结果,所以结果的范围是0到255 */ public final int readUnsignedByte() throws IOException { int ch = in.read(); if (ch < 0) throw new EOFException(); return ch; } /** * 读取两个输入字节并返回一个short值。设ch1为第一个读取字节,ch2为第二个读取字节。 * 返回的值是:(short)((ch1 << 8) + (ch2 << 0)) * * 如ch1为0010 0010,ch2为0001 1001,那么ch1<<8为0010 0010 0000 0000,ch2<<0不变,这样(ch1 << 8) + (ch2 << 0)就拼接成了一个完成的值。 * * @return 读取此输入流的两个字节,将它们解释为一个有符号16位数 */ public final short readShort() throws IOException { int ch1 = in.read(); int ch2 = in.read(); if ((ch1 | ch2) < 0) throw new EOFException(); return (short)((ch1 << 8) + (ch2 << 0)); } /** * 参考readShort方法。 * 问:readUnsignedShort方法与readShort方法代码完全相同,如何保证readUnsignedShort是无符号的? * * @return 此输入流的下两个字节,将它们解释为一个无符号16位整数。 */ 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); } /** * 参考readShort方法。 */ 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)); } /** * 参考readShort方法。 */ 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]; /** * 参考readShort方法。 */ 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)); } /** * 参考DataInput.readFloat方法的介绍 * * 下面是对DataInput.readFloat方法的介绍 * 读取四个输入字节并返回一个float值。 * 实现这一点的方法是:先使用与readInt方法完全相同的方式构造一个int值,然后使用与Float.intBitsToFloat方法完全相同的方式将此int值转换成一个float值。 */ public final float readFloat() throws IOException { return Float.intBitsToFloat(readInt()); } /** * 参考对DataInput.readDouble方法的介绍 * * 下面是对DataInput.readDouble方法的介绍 * 读取八个输入字节并返回一个double值。 * 实现这一点的方法是:先使用与readlong方法完全相同的方式构造一个long值, * 然后使用与Double.longBitsToDouble方法完全相同的方式将此long值转换成一个double值。 */ public final double readDouble() throws IOException { return Double.longBitsToDouble(readLong()); } private char lineBuffer[]; /** * 参考对DataInput.readLine方法的介绍 * * 下面是对DataInput.readLine方法的介绍 * 从输入流中读取下一文本行。 * 该方法读取连续的字节,将每个字节分别转换成一个字符,直到遇到行结尾符或到达末尾;然后以 String 形式返回读取的字符。 */ @Deprecated public final String readLine() throws IOException { //该方法已不建议使用,省略 } /** * 参考对DataInput.readUTF方法的介绍。 * * 下面是对DataInput.readUTF方法的介绍: * 读入一个已使用UTF-8修改版格式编码的字符串。 * readUTF的常规协定是:该方法读取使用UTF-8修改版格式编码的 Unicode字符串的表示形式; * 然后以String的形式返回此字符串。 * * @return 一个Unicode字符串 * @exception EOFException 如果此输入流在读取所有字节之前到达末尾。 * @exception IOException 该流已关闭并且包含的输入流在关闭后不支持读取操作,或者发生其他I/O错误。 * @exception UTFDataFormatException 如果这些字节不表示一个有效的、UTF-8修改版编码的Unicode字符串。 */ public final String readUTF() throws IOException { return readUTF(this); } /** * 从输入流in中读取用UTF-8修改版格式编码的Unicode字符格式的字符串;然后以String形式返回此字符串。 * * @param in 数据输入流 */ public final static String readUTF(DataInput in) throws IOException { //待补充}执行main方法后,控制台会打印出
readBoolean():truereadByte():122readChar():breadShort():123readInt():1111readLong():1233442readUTF():DataOutputStream| 欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) | 黑马程序员IT技术论坛 X3.2 |