DataInputStream和DataOutputStream源码理解


转载:http://wdhdmx.iteye.com/blog/1256318

1.FilterInputStream简介

列出主要的内容。

Java代码   收藏代码
  1. public class FilterInputStream extends InputStream {  
  2.         //对象引用  
  3.         protected volatile InputStream in;  
  4.         protected FilterInputStream(InputStream in) {  
  5.     this.in = in;  
  6.         }  
  7.         public int read() throws IOException {  
  8.     return in.read();  
  9.         }  
  10.         //这个地方的read没用用对象引用in,感觉这个地方用的特别好。  
  11.         public int read(byte b[]) throws IOException {  
  12.     return read(b, 0, b.length);  
  13.         }  
  14.         public int read(byte b[], int off, int len) throws IOException {  
  15.     return in.read(b, off, len);  
  16.         }  
  17. }  

 

FilterInputStream是标准的装饰模式,动态的增加对象的功能 。

2.DataInputStream

Java代码   收藏代码
  1. public class DataInputStream extends FilterInputStream implements DataInput {}  

 继承的接口是DataInput,API文档上说是从二进制流中读取字节,具体内容就不看了,直接看DataInputStream

2.1 构造函数

Java代码   收藏代码
  1. public DataInputStream(InputStream in) {  
  2.         //在上面的FilterInputStream中给变量赋值  
  3.     super(in);  
  4. }  

2.2 read方法

这个类中没有写read()方法,直接调用传入构造函数InputStream对象的read方法,如:FileInputStream的话就是读文件的方法。

下面的两个read带参方法

Java代码   收藏代码
  1. //这两个方法没什么内容  
  2. public final int read(byte b[], int off, int len) throws IOException {  
  3.     return in.read(b, off, len);  
  4. }  
  5. public final int read(byte b[]) throws IOException {  
  6.     return in.read(b, 0, b.length);  
  7. }  

2.3 readFully方法

从输入流中读取一些字节,并将它们存储在缓冲区数组 b 中。

Java代码   收藏代码
  1. public final void readFully(byte b[]) throws IOException {  
  2.     readFully(b, 0, b.length);  
  3. }  
  4.   
  5. public final void readFully(byte b[], int off, int len) throws IOException {  
  6.     if (len < 0)  
  7.         throw new IndexOutOfBoundsException();  
  8.     int n = 0;  
  9.         //首先read返回的是读了几个字节,这个方法在这里没什么意义,直接读入byte数组b。  
  10.         //如果b读不满的话就会继续一个循环,然后报错。也就是说传入的b必须读满  
  11.     while (n < len) {  
  12.         int count = in.read(b, off + n, len - n);  
  13.         if (count < 0)  
  14.         throw new EOFException();  
  15.         n += count;  
  16.     }  
  17. }  

 2.4 skipBytes

Java代码   收藏代码
  1. public final int skipBytes(int n) throws IOException {  
  2.     int total = 0;  
  3.     int cur = 0;  
  4.         //in.skip这个方法返回的是跳过了多少字节,返回的是long类型,这里可以随便转是因为n-total是int型,所以。。  
  5.         //好奇的是为什么不直接返回,还要多一个这样的while循环?想不通。有可能是担心in所对应的对象被覆写,呵呵。  
  6.     while ((total<n) && ((cur = (int) in.skip(n-total)) > 0)) {  
  7.         total += cur;  
  8.     }  
  9.     return total;  
  10. }  

 2.5 各种read类型

直接看

Java代码   收藏代码
  1. //读一个boolean  
  2. public final boolean readBoolean() throws IOException {  
  3.     int ch = in.read();  
  4.     if (ch < 0)  
  5.         throw new EOFException();  
  6.         //这一步可以看出boolean的真实情况,在多数情况下返回的结果是true  
  7.     return (ch != 0);  
  8. }  
  9. //读一个字节,即8位  
  10. public final byte readByte() throws IOException {  
  11.     int ch = in.read();  
  12.     if (ch < 0)  
  13.         throw new EOFException();  
  14.     return (byte)(ch);  
  15. }  
  16. //读一个short类型(16位)  
  17. public final short readShort() throws IOException {  
  18.         int ch1 = in.read();  
  19.         int ch2 = in.read();  
  20.         if ((ch1 | ch2) < 0)  
  21.             throw new EOFException();  
  22.         //进行以为拼装,证实一个字节是八位。后面的一个怎么需要移位0呢,多此一举?还是什么原因?  
  23.         return (short)((ch1 << 8) + (ch2 << 0));  
  24. }  
  25. //读一个字符,也需要拼装(16位)  
  26. public final char readChar() throws IOException {  
  27.         int ch1 = in.read();  
  28.         int ch2 = in.read();  
  29.         if ((ch1 | ch2) < 0)  
  30.             throw new EOFException();  
  31.         return (char)((ch1 << 8) + (ch2 << 0));  
  32. }  
  33. //读一个int类型,很明显是32位  
  34. public final int readInt() throws IOException {  
  35.         int ch1 = in.read();  
  36.         int ch2 = in.read();  
  37.         int ch3 = in.read();  
  38.         int ch4 = in.read();  
  39.         if ((ch1 | ch2 | ch3 | ch4) < 0)  
  40.             throw new EOFException();  
  41.         return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));  
  42. }  

下面是一些占地大的类型

Java代码   收藏代码
  1. private byte readBuffer[] = new byte[8];  
  2. //读long类型,64位,8字节  
  3. public final long readLong() throws IOException {  
  4.         //看来这里是为什么读不满就报错的原因。  
  5.         readFully(readBuffer, 08);  
  6.         //转成long类型相加  
  7.         return (((long)readBuffer[0] << 56) +  
  8.                 ((long)(readBuffer[1] & 255) << 48) +  
  9.         ((long)(readBuffer[2] & 255) << 40) +  
  10.                 ((long)(readBuffer[3] & 255) << 32) +  
  11.                 ((long)(readBuffer[4] & 255) << 24) +  
  12.                 ((readBuffer[5] & 255) << 16) +  
  13.                 ((readBuffer[6] & 255) <<  8) +  
  14.                 ((readBuffer[7] & 255) <<  0));  
  15. }  
  16. //读float,和int一样,4字节,32位  
  17. public final float readFloat() throws IOException {  
  18.     return Float.intBitsToFloat(readInt());  
  19. }  
  20. //和long一样的double  
  21. public final double readDouble() throws IOException {  
  22.     return Double.longBitsToDouble(readLong());  
  23. }  

2.6 readLine 和readUTF

readLine是一个被抛弃的方法,不看了

readUTF是一个自身对应的方法,和writeUTF需要一起看,在下面一起看

3.DataOutputStream

继承关系

Java代码   收藏代码
  1. public class DataOutputStream extends FilterOutputStream implements DataOutput { }  

 FilterOutputStream也是一个标准的装饰模式, 动态的增加对象的功能 。

3.1 各种write方法

Java代码   收藏代码
  1. //写一个布尔,当然1是真,0是假  
  2. public final void writeBoolean(boolean v) throws IOException {  
  3.     out.write(v ? 1 : 0);  
  4.     incCount(1);  
  5. }  
  6. //写一个byte,这个也是占一个字节  
  7. public final void writeByte(int v) throws IOException {  
  8.     out.write(v);  
  9.         incCount(1);  
  10. }  
  11. //写short,两个字节,移位后强取后八位。  
  12. public final void writeShort(int v) throws IOException {  
  13.         out.write((v >>> 8) & 0xFF);  
  14.         out.write((v >>> 0) & 0xFF);  
  15.         incCount(2);  
  16. }  
  17. //再看两个write  
  18. public final void writeInt(int v) throws IOException {  
  19.         out.write((v >>> 24) & 0xFF);  
  20.         out.write((v >>> 16) & 0xFF);  
  21.         out.write((v >>>  8) & 0xFF);  
  22.         out.write((v >>>  0) & 0xFF);  
  23.         incCount(4);  
  24. }  
  25. //这个强转byte和强取后八位是一样的效果。  
  26. private byte writeBuffer[] = new byte[8];  
  27. public final void writeLong(long v) throws IOException {  
  28.         writeBuffer[0] = (byte)(v >>> 56);  
  29.         writeBuffer[1] = (byte)(v >>> 48);  
  30.         writeBuffer[2] = (byte)(v >>> 40);  
  31.         writeBuffer[3] = (byte)(v >>> 32);  
  32.         writeBuffer[4] = (byte)(v >>> 24);  
  33.         writeBuffer[5] = (byte)(v >>> 16);  
  34.         writeBuffer[6] = (byte)(v >>>  8);  
  35.         writeBuffer[7] = (byte)(v >>>  0);  
  36.         out.write(writeBuffer, 08);  
  37.     incCount(8);  
  38. }  
Java代码   收藏代码
  1. //这个就是每一次写操作中添加的次数,这个返回  
  2. public final int size() {  
  3.     return written;  
  4. }  

有空再看看移位的相关知识。

3.2 UTF相关

Java代码   收藏代码
  1.    static int writeUTF(String str, DataOutput out) throws IOException {  
  2.        int strlen = str.length();  
  3. int utflen = 0;  
  4. int c, count = 0;  
  5.        //计算字节数,看来String的每一个字符都是两个字节,16位,也就是4x4  
  6. for (int i = 0; i < strlen; i++) {  
  7.            c = str.charAt(i);  
  8.     if ((c >= 0x0001) && (c <= 0x007F)) {  
  9.     //看来这些是英文等简单字符,只占一个字节  
  10.     utflen++;  
  11.     } else if (c > 0x07FF) {  
  12.     //这个占三个字节,有点想不通那个。(这个和规则有关)  
  13.     utflen += 3;  
  14.     } else {  
  15.     //这个占两个字节。  
  16.     utflen += 2;  
  17.     }  
  18. }  
  19. //一次只能写入么多。65537是最大值,  
  20. if (utflen > 65535)  
  21.     throw new UTFDataFormatException(  
  22.                "encoded string too long: " + utflen + " bytes");  
  23. //分配大小  
  24.        byte[] bytearr = null;  
  25.        if (out instanceof DataOutputStream) {  
  26.            DataOutputStream dos = (DataOutputStream)out;  
  27.            if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))  
  28.                dos.bytearr = new byte[(utflen*2) + 2];  
  29.            bytearr = dos.bytearr;  
  30.        } else {  
  31.            bytearr = new byte[utflen+2];  
  32.        }  
  33. //这个相当于写头信息。我感觉。里面记录这次记录的内容所占字节长度。  
  34. bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);  
  35. bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);    
  36.          
  37.        int i=0;  
  38. //开始连续的简单字符,都是按一个字节存储的。  
  39.        for (i=0; i<strlen; i++) {  
  40.           c = str.charAt(i);  
  41.           if (!((c >= 0x0001) && (c <= 0x007F))) break;  
  42.           bytearr[count++] = (byte) c;  
  43.        }  
  44.   
  45. for (;i < strlen; i++){  
  46.            c = str.charAt(i);  
  47.     if ((c >= 0x0001) && (c <= 0x007F)) {  
  48.     bytearr[count++] = (byte) c;  
  49.     } else if (c > 0x07FF) {  
  50.     //移位都是移6位,每次都要求在对应范围内。  
  51.     // 大于1110 0000 小于 1110 1111  
  52.     bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));           
  53.                // 大于1000 0000 小于 10111111 ,差不多就是这个规则。  
  54.                bytearr[count++] = (byte) (0x80 | ((c >>  6) & 0x3F));  
  55.     bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));  
  56.     } else {  
  57.                //这个大于 11000000 小于 11011111  
  58.     bytearr[count++] = (byte) (0xC0 | ((c >>  6) & 0x1F));  
  59.     bytearr[count++] = (byte) (0x80 | ((c >>  0) & 0x3F));  
  60.     }  
  61. }  
  62. //将包含两个头信息的字符都写入。  
  63.        out.write(bytearr, 0, utflen+2);  
  64.        return utflen + 2;  
  65.    }  

 read的就比写难多了

Java代码   收藏代码
  1. public final static String readUTF(DataInput in) throws IOException {  
  2.      //读前两个字符,得到有多少个字符需要转。  
  3.      int utflen = in.readUnsignedShort();  
  4.      byte[] bytearr = null;  
  5.      char[] chararr = null;  
  6.      if (in instanceof DataInputStream) {  
  7.          DataInputStream dis = (DataInputStream)in;  
  8.          //计算空间够不够,为什么需要申请两倍的空间?  
  9.          if (dis.bytearr.length < utflen){  
  10.              dis.bytearr = new byte[utflen*2];  
  11.              dis.chararr = new char[utflen*2];  
  12.          }  
  13.          chararr = dis.chararr;  
  14.          bytearr = dis.bytearr;  
  15.      } else {  
  16.          bytearr = new byte[utflen];  
  17.          chararr = new char[utflen];  
  18.      }  
  19.   
  20.      int c, char2, char3;  
  21.      int count = 0;  
  22.      int chararr_count=0;  
  23.      //在已读两个字节后读utflen长度的字节。读满  
  24.      in.readFully(bytearr, 0, utflen);  
  25.      //读前面的简单字符。  
  26.      while (count < utflen) {  
  27.          c = (int) bytearr[count] & 0xff;        
  28.          if (c > 127break;  
  29.          count++;  
  30.          chararr[chararr_count++]=(char)c;  
  31.      }  
  32.      //读正常的内容,对应前面的规则。具体就不看了。大致懂就行  
  33.      while (count < utflen) {  
  34.          c = (int) bytearr[count] & 0xff;  
  35.          switch (c >> 4) {  
  36.              case 0case 1case 2case 3case 4case 5case 6case 7:  
  37.                  count++;  
  38.                  chararr[chararr_count++]=(char)c;  
  39.                  break;  
  40.              case 12case 13:  
  41.                  count += 2;  
  42.                  if (count > utflen)  
  43.                      throw new UTFDataFormatException(  
  44.                          "malformed input: partial character at end");  
  45.                  char2 = (int) bytearr[count-1];  
  46.                  if ((char2 & 0xC0) != 0x80)  
  47.                      throw new UTFDataFormatException(  
  48.                          "malformed input around byte " + count);   
  49.                  chararr[chararr_count++]=(char)(((c & 0x1F) << 6) |   
  50.                                                  (char2 & 0x3F));    
  51.                  break;  
  52.              case 14:  
  53.                  /* 1110 xxxx  10xx xxxx  10xx xxxx */  
  54.                  count += 3;  
  55.                  if (count > utflen)  
  56.                      throw new UTFDataFormatException(  
  57.                          "malformed input: partial character at end");  
  58.                  char2 = (int) bytearr[count-2];  
  59.                  char3 = (int) bytearr[count-1];  
  60.                  if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80))  
  61.                      throw new UTFDataFormatException(  
  62.                          "malformed input around byte " + (count-1));  
  63.                  chararr[chararr_count++]=(char)(((c     & 0x0F) << 12) |  
  64.                                                  ((char2 & 0x3F) << 6)  |  
  65.                                                  ((char3 & 0x3F) << 0));  
  66.                  break;  
  67.              default:  
  68.                  throw new UTFDataFormatException(  
  69.                      "malformed input around byte " + count);  
  70.          }  
  71.      }  
  72.      // The number of chars produced may be less than utflen  
  73.      return new String(chararr, 0, chararr_count); 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
主要特性Java 语言是简单的:Java 语言的语法与 C 语言和 C++ 语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java 丢弃了 C++ 中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地,Java 语言不使用指针,而是引用。并提供了自动分配和回收内存空间,使得程序员不必为内存管理而担忧。Java 语言是面向对象的:Java 语言提供类、接口和继承等面向对象的特性,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为 implements)。Java 语言全面支持动态绑定,而 C++语言只对虚函数使用动态绑定。总之,Java语言是一个纯的面向对象程序设计语言。Java语言是分布式的:Java 语言支持 Internet 应用的开发,在基本的 Java 应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括 URL、URLConnection、Socket、ServerSocket 等。Java 的 RMI(远程方法激活)机制也是开发分布式应用的重要手段。Java 语言是健壮的:Java 的强类型机制、异常处理、垃圾的自动收集等是 Java 程序健壮性的重要保证。对指针的丢弃是 Java 的明智选择。Java 的安全检查机制使得 Java 更具健壮性。Java语言是安全的:Java通常被用在网络环境中,为此,Java 提供了一个安全机制以防恶意代码的攻击。除了Java 语言具有的许多安全特性以外,Java 对通过网络下载的类具有一个安全防范机制(类 ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制(类 SecurityManager)让 Java 应用设置安全哨兵。Java 语言是体系结构中立的:Java 程序(后缀为 java 的文件)在 Java 平台上被编译为体系结构中立的字节码格式(后缀为 class 的文件),然后可以在实现这个 Java 平台的任何系统中运行。这种途径适合于异构的网络环境和软件的分发。Java 语言是可移植的:这种可移植性来源于体系结构中立性,另外,Java 还严格规定了各个基本数据类型的长度。Java 系统本身也具有很强的可移植性,Java 编译器是用 Java 实现的,Java 的运行环境是用 ANSI C 实现的。Java 语言是解释型的:如前所述,Java 程序在 Java 平台上被编译为字节码格式,然后可以在实现这个 Java 平台的任何系统中运行。在运行时,Java 平台中的 Java 解释器对这些字节码进行解释执行,执行过程中需要的类在联接阶段被载入到运行环境中。Java 是高性能的:与那些解释型的高级脚本语言相比,Java 的确是高性能的。事实上,Java 的运行速度随着 JIT(Just-In-Time)编译器技术的发展越来越接近于 C++。Java 语言是多线程的:在 Java 语言中,线程是一种特殊的对象,它必须由 Thread 类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为 Thread(Runnable) 的构造子类将一个实现了 Runnable 接口的对象包装成一个线程,其二,从 Thread 类派生出子类并重写 run 方法,使用该子类创建的对象即为线程。值得注意的是 Thread 类已经实现了 Runnable 接口,因此,任何一个线程均有它的 run 方法,而 run 方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java 语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为 synchronized)。Java 语言是动态的:Java 语言的设计目标之一是适应于动态变化的环境。Java 程序需要的类能够动态地被载入到运行环境,也可以通过网络来载入所需要的类。这也有利于软件的升级。另外,Java 中的类有一个运行时刻的表示,能进行运行时刻的类型检查。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值