本篇讲述的是java io包中的DataInputStream和DataOutputStream。
这两个类都属于java io中的包装类,为基础流提供了丰富的读写方法,可以将java中的数据类型轻松地写入流中。
下面还是先贴出源码进行简单的分析:
DataInputStream.java:
package java.io;
public class DataInputStream extends FilterInputStream implements DataInput {
/**
* 一个带一个参数的构造方法,传入的参数为一个InputStream对象。内部本质是调用父类FilterInputStream的构造方法。
*/
public DataInputStream(InputStream in) {
super(in);
}
//定义了两个数组,一个是byte型数组,一个是char型数组,初始容量都为80,用于后面readUTF方法中提供缓存数组。
private byte bytearr[] = new byte[80];
private char chararr[] = new char[80];
/**
* 每次读取多个字节的数据,传入的参数为一个byte型数组,读取的数据会填充到该数组中区,最终返回实际读取的字节数。
*/
public final int read(byte b[]) throws IOException {
return in.read(b, 0, b.length);
}
/**
* 每次读取多个字节的数据,有3个传入的参数,第一个参数为一个byte型数组,用于装取读取到的字节数据,第二和第三个参数都是int型数据,分别表示读取的起点,
* 和读取的长度。
*/
public final int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
/**
* 每次读取多个字节的数据,传入的参数为一个byte型数组,用于装取读取的字节数据。与上面read方法的区别在于该方法必须等到传入的字节数组填满或者读取到文件
* 结尾或者抛出异常时才会返回,最终返回实际读取的字节数。
*/
public final void readFully(byte b[]) throws IOException {
readFully(b, 0, b.length);
}
/**
* 每次读取多个字节的数据,传入的第一个参数为一个byte型数组,用于装取读取的字节数据,第二个参数和第三个参数都为int型数据,分别代表着读取的起点和读取
* 的长度。
*/
public final void readFully(byte b[], int off, int len) throws IOException {
//对传入的参数进行安全检测,如果len<0,则抛出相应异常。
if (len < 0)
throw new IndexOutOfBoundsException();
//通过一个循环读取指定长度len的数据,直到读取完毕或者读到文件结尾时才返回。
int n = 0;
while (n < len) {
int count = in.read(b, off + n, len - n);
if (count < 0)
throw new EOFException();
n += count;
}
}
/**
* 该方法用于跳过指定长度的字节数。最终返回实际跳过的字节数。
*/
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型数据,原理是读取一个字节的数据,将其与0比较,非0为true,0为false,最终返回比较结果。
*/
public final boolean readBoolean() throws IOException {
int ch = in.read();
if (ch < 0)
throw new EOFException();
return (ch != 0);
}
/**
* 每次读取一个byte型数据,原理是每次读取一个字节的数据,然后将其转换成byte型数据并返回。
*/
public final byte readByte() throws IOException {
int ch = in.read();
if (ch < 0)
throw new EOFException();
return (byte)(ch);
}
/**
* 每次读取一个无符号的byte型数据,原理是每次读取一个字节的数据,最终将其返回。
*/
public final int readUnsignedByte() throws IOException {
int ch = in.read();
if (ch < 0)
throw new EOFException();
return ch;
}
/**
* 每次读取一个short类型的的数据,原理是每次读取两个字节的数据,分别代表着short类型数据的高八位和低八位,最终将其组合成一个short型数据并返回。
*/
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));
}
/**
* 每次读取一个无符号short类型的数据,原理是每次读取两个字节的数据,分别代表着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类型的数据,原理是每次读取两个字节的数据,分别代表着char类型数据高八位和低八位,最终将其组合并转换成一个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类型的数据,原理是每次读取4个字节的数据,每个字节的数据依次从int型数据的最高位开始填充,最终将拼装后的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));
}
//定义了一个字节数组,容量为8,用于在readLong方法中调用读取多个字节的read方法时,提供缓存数组。
private byte readBuffer[] = new byte[8];
/**
* 每次读取一个long类型的数据,其工作原理是通过readFully方法一次读取8个字节的数据,然后将读取的数据依次从long型数据的最高位开始填充,最终将填充完毕