zoukankan      html  css  js  c++  java
  • Java之IO(四)DataInputStream和DataOutputStream

      转载请注明源出处:http://www.cnblogs.com/lighten/p/6986155.html

    1.前言

      DataInputStream和DataOutputStream分别继承了FilterInputStream和FilterOutputStream,这块内容在第二节介绍BufferedInputStream和BufferedOutputStream的时候介绍过了,这里不再介绍。Java中针对于IO有许多现有的封装类可以使用,但是每个封装类都有各自的特点,使用场景不一样。本章介绍的这对IO还实现了其它的接口,DataInput和DataOutput。之前所讲到的流都是字节流,但是实际上对我们而言,字节流是没有什么太大的意义,单个字节人是无法知道含义的,所以通常需要对字节进行解析,获取真正有价值的意义。而这对流就完成了一个对基本数据类型(boolean,byte,unsignedByte,short,unsignedShort,char,int,long,float,double)的写入和读取和一些常用的读一行,读取UTF格式等方法,不需要我们自己重复写。当然Java的IO体系针对字符流有专门的Reader和Writer进行操作字符流。这在之后的章节进行介绍。

    2.DataInputStream

      DataInputStream需要接受一个输入源流。

      

      

      

      这些基础的InputStream的方法都是使用输入源的基本方法。

      这些方法其实也十分的简单,都是针对每个类型的特点,将其读取出来,当然写入流的时候也要这样才行。

    // 读取一个整形,根据是否为0返回boolean值
    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是占两个字节,把第一读出来的左移8位到高8位。最后强转成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也是两个字节,方法和short一样,最后强转成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个字节,第一个左移24位到最高8位,之后的依次就是最后的结果
    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));
    }
    
    // long是8个字节,读入一个数组,然后按照一定的转换方式进行转换
    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是调用readInt再通过Float的方法来转成float
    public final float readFloat() throws IOException {
            return Float.intBitsToFloat(readInt());
    }
    
    // double与float类似,不过是8位所以用readLong()
    public final double readDouble() throws IOException {
            return Double.longBitsToDouble(readLong());
    }
    

      最后的readline()方法已经被废弃了。不过可以看看源代码,比较有意思:

    public final String readLine() throws IOException {
            char buf[] = lineBuffer;
    
            if (buf == null) {
                buf = lineBuffer = new char[128];
            }
    
            int room = buf.length;
            int offset = 0;
            int c;
    
    loop:   while (true) {
                switch (c = in.read()) {
                  case -1:
                  case '
    ':
                    break loop;
    
                  case '
    ':
                    int c2 = in.read();
                    if ((c2 != '
    ') && (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, 0, offset);
        }
    

      用了一个无限循环,读取到换行符才进行break,因为换行符根据操作系统不同,有两种' '和' '。所以' '的时候还判断了一下后面的字符是不是 。不是的话使用了一个PushbackInputStream,这个很有意思,一般流读取了是无法反悔的(不能再次读取),但是专门有了个反悔的输入流。这个其实也简单,和BufferedInputStream原理类似,就是里面有个数组,不同的是BufferedInputStream是为了存从流中取得的字节,PushbackInputStream是放入反悔的字节,pos计数还是从缓存大小倒数的,这也是个不同点。最后是将流读取成UTF格式的字符串。但是只限于DataOutputStream输出的,其解析有固定的格式,前一个Int是字符串长度。

    3.DataOutputStream

      

      DataOutputStream也需要一个输出源,里面有一个计数字段written,计算写入了多少字节的数据,是int类型。如果长度超多了int类型的最大值,就会使用Integer.MAX_VALUE来标记。

      超过了就会变成负数,就是变成了Integer.MAX_VALUE。接下来就是与DataInputStream解析方法对应的写入方法了。

    public final void writeBoolean(boolean v) throws IOException {
            out.write(v ? 1 : 0);
            incCount(1);
    }
    
    public final void writeByte(int v) throws IOException {
            out.write(v);
            incCount(1);
    }
    
    public final void writeShort(int v) throws IOException {
            out.write((v >>> 8) & 0xFF);
            out.write((v >>> 0) & 0xFF);
            incCount(2);
    }
    
    public final void writeChar(int v) throws IOException {
            out.write((v >>> 8) & 0xFF);
            out.write((v >>> 0) & 0xFF);
            incCount(2);
    }
    
    public final void writeInt(int v) throws IOException {
            out.write((v >>> 24) & 0xFF);
            out.write((v >>> 16) & 0xFF);
            out.write((v >>>  8) & 0xFF);
            out.write((v >>>  0) & 0xFF);
            incCount(4);
    }
    
    public final void writeLong(long v) throws IOException {
            writeBuffer[0] = (byte)(v >>> 56);
            writeBuffer[1] = (byte)(v >>> 48);
            writeBuffer[2] = (byte)(v >>> 40);
            writeBuffer[3] = (byte)(v >>> 32);
            writeBuffer[4] = (byte)(v >>> 24);
            writeBuffer[5] = (byte)(v >>> 16);
            writeBuffer[6] = (byte)(v >>>  8);
            writeBuffer[7] = (byte)(v >>>  0);
            out.write(writeBuffer, 0, 8);
            incCount(8);
    }
    
    public final void writeFloat(float v) throws IOException {
            writeInt(Float.floatToIntBits(v));
    }
    
    public final void writeDouble(double v) throws IOException {
            writeLong(Double.doubleToLongBits(v));
    }
    

      还有一些方法比如writeBytes(String)和writeUTF方法就不介绍了。

    4.例子与结语

            @Test
    	public void test() throws IOException {
    		ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
    		DataOutputStream dos = new DataOutputStream(baos);
    		dos.writeByte(1);
    		dos.writeInt(234);
    		dos.writeShort(56);
    		dos.writeLong(789L);
    		dos.writeDouble(11.11);
    		dos.writeFloat(22.22f);
    		dos.writeChar('a');
    		dos.writeBoolean(false);
    		dos.writeUTF("你好!");
    		dos.close();
    		ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    		DataInputStream dis = new DataInputStream(bais);
    		System.out.println(dis.readByte());
    		System.out.println(dis.readInt());
    		System.out.println(dis.readShort());
    		System.out.println(dis.readLong());
    		System.out.println(dis.readDouble());
    		System.out.println(dis.readFloat());
    		System.out.println(dis.readChar());
    		System.out.println(dis.readBoolean());
    		System.out.println(dis.readUTF());
    		dis.close();
    	}

      上述就是一个简单的例子了。这里还需要说明的是:这对流是线程不安全的,如果你要在多线程下使用,需要自己保证线程安全。

      

  • 相关阅读:
    2.12 使用@DataProvider
    2.11 webdriver中使用 FileUtils ()
    Xcode8 添加PCH文件
    The app icon set "AppIcon" has an unassigned child告警
    Launch Image
    iOS App图标和启动画面尺寸
    iPhone屏幕尺寸、分辨率及适配
    Xcode下载失败 使用已购项目页面再试一次
    could not find developer disk image
    NSDate与 NSString 、long long类型的相互转化
  • 原文地址:https://www.cnblogs.com/lighten/p/6986155.html
Copyright © 2011-2022 走看看