全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

Java 中的 DataInputStream 介绍_动力节点Java学院整理

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):0x8f
charToHexString(0x8FCF):0x8fcf
readBoolean():true
readByte():0x41
readChar():0x4243
readShort():0x4445
readInt():0x12345678
readLong():0xfedcba987654321
readUTF():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的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!


# java  # datainputstream  # java序列化与ObjectOutputStream和ObjectInputStream的实例详解  # Java中的InputStreamReader和OutputStreamWriter源码分析_动力节  # 详解PipedInputStream和PipedOutputStream_动力节点Java学院整理  # java 中InputStream  # String  # File之间的相互转化对比  # Java的DataInputStream和DataOutputStream数据输入输出流  # Java中的BufferedInputStream与BufferedOutputStream使用示例  # Java实现inputstream流的复制代码实例  # 转换成  # 应是  # 第一个  # 的是  # 应用程序  # 四字  # 而不是  # 只会  # 可以使用  # 这么做  # 会将  # 转换为  # 小编  # 跳过  # 长度为  # 是一个  # 情况下  # 是有  # 在此  # 是这样 


相关文章: 微信小程序 五星评分(包括半颗星评分)实例代码  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  深圳网站制作培训,深圳哪些招聘网站比较好?  高防服务器如何保障网站安全无虞?  如何通过西部建站助手安装IIS服务器?  建站之星代理费用多少?最新价格详情介绍  如何解决ASP生成WAP建站中文乱码问题?  Android自定义listview布局实现上拉加载下拉刷新功能  如何配置支付宝与微信支付功能?  如何在阿里云高效完成企业建站全流程?  保定网站制作方案定制,保定招聘的渠道有哪些?找工作的人一般都去哪里看招聘信息?  C++如何使用std::optional?(处理可选值)  如何通过FTP服务器快速搭建网站?  成都响应式网站开发,dw怎么把手机适应页面变成网页?  怎么用手机制作网站链接,dw怎么把手机适应页面变成网页?  网站按钮制作软件,如何实现网页中按钮的自动点击?  企业在线网站设计制作流程,想建设一个属于自己的企业网站,该如何去做?  如何通过可视化优化提升建站效果?  北京制作网站的公司,北京铁路集团官方网站?  潍坊网站制作公司有哪些,潍坊哪家招聘网站好?  威客平台建站流程解析:高效搭建教程与设计优化方案  深入理解Android中的xmlns:tools属性  代刷网站制作软件,别人代刷火车票靠谱吗?  深圳网站制作设计招聘,关于服装设计的流行趋势,哪里的资料比较全面?  广平建站公司哪家专业可靠?如何选择?  建站168自助建站系统:快速模板定制与SEO优化指南  建站VPS推荐:2025年高性能服务器配置指南  如何在Golang中处理模块冲突_解决依赖版本不兼容问题  惠州网站建设制作推广,惠州市华视达文化传媒有限公司怎么样?  广州顶尖建站服务:企业官网建设与SEO优化一体化方案  香港服务器网站生成指南:免费资源整合与高速稳定配置方案  高端企业智能建站程序:SEO优化与响应式模板定制开发  如何访问已购建站主机并解决登录问题?  如何用y主机助手快速搭建网站?  Thinkphp 中 distinct 的用法解析  网站制作新手教程,新手建设一个网站需要注意些什么?  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  昆明高端网站制作公司,昆明公租房申请网上登录入口?  小说建站VPS选用指南:性能对比、配置优化与建站方案解析  教育培训网站制作流程,请问edu教育网站的域名怎么申请?  专业型网站制作公司有哪些,我设计专业的,谁给推荐几个设计师兼职类的网站?  建站之星CMS五站合一模板配置与SEO优化指南  如何通过PHP快速构建高效问答网站功能?  专业网站制作企业网站,如何制作一个企业网站,建设网站的基本步骤有哪些?  如何在宝塔面板中创建新站点?  如何选择可靠的免备案建站服务器?  家庭建站与云服务器建站,如何选择更优?  c++ stringstream用法详解_c++字符串与数字转换利器  桂林网站制作公司有哪些,桂林马拉松怎么报名?  北京营销型网站制作公司,可以用python做一个营销推广网站吗? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。