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();
    	}

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

      

  • 相关阅读:
    验证身份证
    base64.js
    mysql常用操作
    drop、truncate和delete的区别
    安装mysql
    一些常用计算
    nuxt+vant+rem项目构建
    vue2安装sass 预编译
    vant ui rem配置流程
    关于vue项目和内嵌iframe页面之间的通信问题
  • 原文地址:https://www.cnblogs.com/lighten/p/6986155.html
Copyright © 2011-2022 走看看