IO流-DataInputStream分析

DataInputStream介绍

io流就相当于读写数据的一个管道.主要分为输入流和输出流,分别对应读数据和写数据.下面我们将介绍一下DataInputStream

1.继承关系

class DataInputStream extends FilterInputStream implements DataInput {
//数据输入流
//继承FilterInputStream类
//实现DataInput接口

2.构造方法

public DataInputStream(InputStream in) {//处理流
        super(in);
    }
  • 有参构造方法传入的基础输入流

3.内部变量

 	private byte bytearr[] = new byte[80];//字节数组
    private char chararr[] = new char[80];//字符数组

4.内部方法


	read(byte b[])---从数据输入流读取数据存储到字节数组b中
	
	read(byte b[],int off,in len)---从数据输入流中读取数据存储到数组b里面,起始位置off,长度len个字节

	readFully(byte b[])---从数据输入流中循环读取b.length个字节到数组b

	readFully(byte b[],int off,in len )---从数据输入流中循环读取len个字节到字节数组b中,起始位置off

	skipBytes(int b)---跳过n个字节

	readBoolean()---从数据输入流读取布尔类型的值

	readByte()---从数据输入流中读取一个字节

	readUnsignedByte()---从数据输入流中读取一个无符号的字节,返回值为int类型
	
	readShort()---从数据输入流读取一个short类型数据

	readUnsignedShort()---从数据输入流读取一个无符号的short类型数据

	readChar()---从数据输入流中读取一个字符数据

	readInt()---从数据输入流中读取一个int类型数据

	readLong()---从数据输入流中读取一个long类型的数据

	readFloat()---从数据输入流中读取一个float类型的数据

	readDouble()---从数据输入流中读取一个double类型的数据

	readUTF()---从数据输入流中读取用UTF-8格式编码的UniCode字符格式的字符串
	

完整源码分析:

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];
 
  // 将数据从数据输入流中读取到字节数组b中
  public final int read(byte b[]) throws IOException {
    return in.read(b, 0, b.length);
  }
 
  // 将数据从数据输入流中读取到字节数组b中,b的起始位置是off,长度是len
  public final int read(byte b[], int off, int len) throws IOException {
    return in.read(b, off, len);
  }
 
  // 从数据输入流中读取数据,填充字节数组b.
  public final void readFully(byte b[]) throws IOException {
    readFully(b, 0, b.length);
  }
 
  // 将数据从数据输入流读取到字节数组b中,起始位置是off,长度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;
  }
 
  // 从数据输入流中读取布尔类型.
  public final boolean readBoolean() throws IOException {
    int ch = in.read();
    if (ch < 0)
      throw new EOFException();
    return (ch != 0);
  }
 
  // 从数据输入流中读取一个字节
  public final byte readByte() throws IOException {
    int ch = in.read();
    if (ch < 0)
      throw new EOFException();
    return (byte) (ch);
  }
 
  // 从数据输入流中读取一个无符号的字节
  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 ch1 = in.read();
    int ch2 = 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);
  }
 
  // 从数据输入流中读取一个字符数据
  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[];
 
  // 从数据输入流中读取utf编码的数据
  public final String readUTF() throws IOException {
    return readUTF(this);
  }
 
  public final static String readUTF(DataInput in) throws IOException {
    int utflen = in.readUnsignedShort();
    byte[] bytearr = null;
    char[] chararr = null;
    // 先要判断in是否数据输入流类型
    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数组中.长度是utflen
    in.readFully(bytearr, 0, utflen);
    // 根据字节范围不会超过127,超过的情况下,说明字节数组里面存储超过了一个字节.
    while (count < utflen) {
      c = (int) bytearr[count] & 0xff;
      if (c > 127)
        break;
      count++;
      // 一个字节的情况,将c转换成字符存储到字符数组中.
      chararr[chararr_count++] = (char) c;
    }
    // 数据输出流使用utf-8编码写出数据时,会进行编码.
    // 需要根据utf-8编码规则,判断对应每个"字符"c占用几个字节.
    // 1个字节的编码格式:0xxxxxxx
    // 2个字节的编码格式:110x xxxxx 10xx xxxx
    // 3个字节的编码格式:1110 xxxx 10xx xxxx 10xx xxxx
    // 4个字节的编码格式:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    while (count < utflen) {
      c = (int) bytearr[count] & 0xff;
      // 需要先判断utf有几个字节.
      // 将字节数组的总第一个字节右移4位,0000xxxx.那么xxxx,最大值就是1111,10进制是15
      // 最小是0000,十进制就是0.根据字节数组里面的第一个字节的前四位可以看出"UTF"占用了几个字节
      switch (c >> 4) {
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
          /* 0xxxxxxx */
          // utf编码是一个字节,0xxxxxxx右移4位,00000xxx,
          // 最小值是0,最大值是111,对应十进制范围就是0-7
          count++;
          chararr[chararr_count++] = (char) c;
          break;
        case 12:
        case 13:
          /* 110x xxxx 10xx xxxx */
          // utf编码是两个字节的情况,将首字节110xxxxx右移4位,是110x,
          // 最小值是1100,最大值是1100,对应十进制是12,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));
          break;
        case 14:
          /* 1110 xxxx 10xx xxxx 10xx xxxx */
          // utf编码是三个字节的情况下,将首字节1110xxxx右移4位,是1110
          // 十进制是14
          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:
          // 此外四个字节或者首字节是10开头的情况,不做转化
          /* 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);
  }
}

5.IO流常见问题

1.什么是java序列化,如何实现java序列化?

  序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化(将对象转换成二进制)。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题。

注解:当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

  将需要序化的类实现Serializable接口就可以了,该接口没有任何方法,可以理解为一个标记,即表明这个类可以序列化。注意的是被关键字static、transient修饰的变量不能被序列化。在被序列化后,transient修饰的变量会被设为初始值。如int型的是0、对象型的是null.

1.概念

  序列化:把Java对象转换为字节序列的过程。
  反序列化:把字节序列恢复为Java对象的过程。

2.用途

  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

2.DataInputStream的应用场景

  针对八种基本数据类型的文件操作流

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值