zoukankan      html  css  js  c++  java
  • javaIO--数据流之IO流与字节流

    0、IO流

    0.1、IO(Input Output)流的概念

    Java中将不同设备之间的数据传输抽象为“流”:Stream
    设备指的是:磁盘上的文件,网络连接,另一个主机等等

    按流向分:输入流,输出流:都是针对内存来说的

    1. 输入流,只能从其中读取数据
    2. 输出流,只能把数据放入其中

    按每次处理的数据单位分:字节流,字符流
    1.字节流:每次处理一个字节
    2.字符流:每次处理一个字符

    0.2、IO流抽象基类

    通常流的分类,如果没有特定指出,都是按操作数据单位来说的

    字节流:两个方向
    InputStream:输入字节流
    OutputStream:输出字节流

    字节流继承图:

    字符流:两个方向
    Reader:输入字符流
    Writer:输出字符流

    字符流继承图:

    1、字节流

    1.1字节输出流抽象基类:OutputStream

    1.1.1 FileOutputStream实现类

    构造方法:(输出流会自动创建输出对象)
    FileOutputStream(File file)
      通过一个File对象创建一个文件输出流对象
    FileOutputStream(String name)
      通过一个字符串构建一个文件输出流对象
    FileOutputStream(File file,boolean append)
      通过文件对象创建文件输出流对象,并指定是否追加
    FileOutputStream(String name,boolean append)
      通过一个字符串构建一个文件输出流对象,并指定是否追加

    note:如果没有实际对象,对对象的操作并不会作用于实际文件

    写出数据到流对象:
    void write(byte[] bytes)
      一次写一个字节数组的数据
    void write(int b)
      一次写一个字节
    void write(byte[] bytes,int off,int len)
      一次写一个字节数组的一部分

    关闭流对象:
    void close()
      关闭此文件输出流并释放与此流有关的所有系统资源

    关闭流的两个作用:
    1.让流不能再继续使用
    2.释放和此流相关的系统资源

    1.1.2 FileInputStream实现类

    构造方法:(必须要求输入对象事先存在)
    FileInputStream(File file)
      通过File对象创建一个文件输入流对象 FileInputStream(String name)
      通过一个字符串创建一个文件输入流对象 String可以是完整路径字符串
    int read()
      从输入流中读取一个字节
    int read(byte[] b)
      从输入流中读取字节,放到字节数组中,返回字节个数
    int read(byte[] b,int off,int len)
      从输入流中读取字节,放到字节数组中,只放到指定位置(不常用)

    1.1.3自带关闭资源的try语句块

    为了替换finally臃肿的写法,JDK7出现了自带关闭资源的try语句块,可以不用显式的写finally语句。
    用法:
    将需要关闭的资源定义或者初始化语句放到try后的括号里,程序会自动关闭这些资源,前提是这些类实现了AutoCloseable接口或者Closeable接口
    格式:

    try(需要自动关闭的资源声明或者初始化){
        //正常逻辑语句
    }

    案例:字节读取

    1.一次读取一个字节
    2.用循环改进读取字节
    3.简化循环读取字节
    4.一次读取一个字节数组
    5.加上异常处理读取字节数组
    6.改进异常处理读取字节数组
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    
    /*
     * FileInputStream(File name)
     * FileInputStream(String name)
     */
    public class FileInputStreamDemo {
    
        public static void main(String[] args) throws Exception {
            //输入流关联的文件必须事先存在,否则异常,输出流目标文件可以自动创建
            FileInputStream fis = new FileInputStream(new File("a.txt"));
            
    //        FileInputStream fis2 = new FileInputStream("a.txt");
            
            //一次读取一个字节:
    //        int b = fis.read();
    //        System.out.println(b);
            /*
            b = fis.read();
            System.out.println(b);
            b = fis.read();
            System.out.println(b);
            b = fis.read();
            System.out.println(b);
            b = fis.read();
            System.out.println(b);
            */
            //用循环改进
            /*
            int b = 0;
            while(true){
                b = fis.read();
                if(b == -1){
                    break;
                }else{
                    System.out.println(b);
                }
            }
            */
            //最终代码
    //        int b = 0;
    //        while((b = fis.read()) != -1){
    //            System.out.println(b);
    //        }
            
            //一次读取一个字节数组
            /*
            byte[] bys = new byte[1024];
            int len = fis.read(bys);
            System.out.println(len);
            
            //用字节数组构建字符串
            String str = new String(bys, 0, len);
            System.out.println(str);
            */
            
            //循环读取数据
            int len = 0;
            byte[] bys = new byte[1024];
            while((len = fis.read(bys) + test()) != -1){
                System.out.print(new String(bys,0,len));
            }
            
            //释放资源
            fis.close();
    
        }
    
        public static int test(){
            System.out.println("方法被调用了");
            return 0;
        }
        
    }
    字节读取
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.IOException;
    
    /*
     * 加上异常处理的程序
     * 
     * 1.7后新特性:自带关闭资源的try块
     * 
     */
    public class FileInputStreamDemo2 {
    
        public static void main(String[] args) {
            /*
            //提升作用域
            FileInputStream fis = null;
            try {
                fis = new FileInputStream("a.txt");//此条语句有可能不执行成功
                
                //
                int len = 0;
                byte[] bys = new byte[1024];
                while((len = fis.read(bys)) != -1){
                    System.out.print(new String(bys,0,len));
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }finally{
                //用来释放非内存资源
                //释放资源
                //非空判断
                if(fis != null){
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                
                //如果有多个变量,继续关闭
            }
    
    */
            
            //自动关闭资源的try块
            try(
                    FileInputStream fis = new FileInputStream("a.txt");
                    //
                    ){
                //正常的逻辑语句
                int len = 0;
                byte[] bys = new byte[1024];
                while((len = fis.read(bys)) != -1){
                    System.out.print(new String(bys,0,len));
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            
        }
    
    }
    异常处理改进

    案例:写出数据到流

    import java.io.File;
    import java.io.FileOutputStream;
    
    /*
     * FileOutputStream(File name)
     * FileOutputStream(File name,boolean append)
     * FileOutputStream(String name)
     * FileOutputStream(String name,boolean append)
     * 
     *    创建对象 --> 使用写出方法写出数据到流 --> 释放资源
     *
     *    写入到文件中的数据.如果使用记事本等程序打开,会经过转码的过程. ( 字节-->字符 )
     */
    public class FileOutputStreamDemo1 {
    
        public static void main(String[] args) throws Exception {
            //
            FileOutputStream fos = new FileOutputStream(new File("a.txt"),true);
            /*
            //
            FileOutputStream fos2 = new FileOutputStream(new File("a.txt"), true);
            
            //
            FileOutputStream fos3 = new FileOutputStream("a.txt");
            
            //
            FileOutputStream fos4 = new FileOutputStream("a.txt",true);
    */
            //一次写一个字节
    //        fos.write(98);
            
            //一次写一个字节数组
    //        byte[] bys = {97,98,99,100,101,102,103,104};        
    //        fos.write(bys);
            
            //一次写一个字节数组的一部分
    //        fos.write(bys, 2, 3);
            
            //实现换行
            fos.write("abc
    def".getBytes());//使用系统默认的字符集编码成字节数组 :
            
            //释放资源
            fos.close();
            
            //流关闭之后不能再写数据
    //        fos.write(97);
            
        }
    
    }
    写出数据到流

    案例:文件的复制

    思路:
    1.使用源文件创建文件输入流对象
    2.使用目标文件创建文件输出流对象
    3.复制数据
    4.关闭资源
    
    实现同一个项目路径下的文本文件的复制
    实现不同路径下的文本文件的复制
    实现图片的复制
    实现mp3的复制 

    1.1.4 自带缓冲区的字节流

    一次读取(或者写入)一个字节数组的数据在效率上提升了很多,字节数组实际上相当于一个缓冲区。
    Java提供了自带缓冲区的流,不必自己再定义额外的字节数组充当缓冲区了。

    自带缓冲区的字节输入流     vs      自带缓冲区的字节输出流
    BufferedInputStream                   BufferedOutputStream

     

     

    package java.io;
    
    public class BufferedOutputStream extends FilterOutputStream {
    
        protected byte buf[];
    
        protected int count;
    
        public BufferedOutputStream(OutputStream out) {
            this(out, 8192);
        }
    
        public BufferedOutputStream(OutputStream out, int size) {
            super(out);
            if (size <= 0) {
                throw new IllegalArgumentException("Buffer size <= 0");
            }
            buf = new byte[size];
        }
    
        /** Flush the internal buffer */
        private void flushBuffer() throws IOException {
            if (count > 0) {
                out.write(buf, 0, count);
                count = 0;
            }
        }
    
    
        public synchronized void write(int b) throws IOException {
            if (count >= buf.length) {
                flushBuffer();
            }
            buf[count++] = (byte)b;
        }
    
    
        public synchronized void write(byte b[], int off, int len) throws IOException {
            if (len >= buf.length) {
                /* If the request length exceeds the size of the output buffer,
                   flush the output buffer and then write the data directly.
                   In this way buffered streams will cascade harmlessly. */
                flushBuffer();
                out.write(b, off, len);
                return;
            }
            if (len > buf.length - count) {
                flushBuffer();
            }
            System.arraycopy(b, off, buf, count, len);
            count += len;
        }
    
    
        public synchronized void flush() throws IOException {
            flushBuffer();
            out.flush();
        }
    }
    BufferedOutputStream
    package java.io;
    import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
    
    
    public
    class BufferedInputStream extends FilterInputStream {
    
        private static int DEFAULT_BUFFER_SIZE = 8192;
    
        private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
    
        protected volatile byte buf[];
    
        private static final
            AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
            AtomicReferenceFieldUpdater.newUpdater
            (BufferedInputStream.class,  byte[].class, "buf");
    
        /**
         * The index one greater than the index of the last valid byte in the buffer.
         * 0<count<buf.length
         */
        protected int count;
    
        /**
         * The current position in the buffer. This is the index of the next character to be read from the buf[].
         * 0<pos<count.  buf[pos] is the next byte to be supplied as input;
         */
        protected int pos;
    
        /**
         * The value of the pos field at the time the last
         * mark method was called.
         * This value is always in the range -1 through pos.
         * If there is no marked position in  the input
         * stream, this field is -1. If
         * there is a marked position in the input
         * stream,  then buf[markpos]
         * is the first byte to be supplied as input
         * after a reset operation. If
         * markpos is not -1,
         * then all bytes from positions buf[markpos]
         * through  buf[pos-1] must remain
         * in the buffer array (though they may be
         * moved to  another place in the buffer array,
         * with suitable adjustments to the values
         * of count,  pos,
         * and markpos); they may not
         * be discarded unless and until the difference
         * between pos and markpos
         * exceeds marklimit.
         *
         * @see     java.io.BufferedInputStream#mark(int)
         * @see     java.io.BufferedInputStream#pos
         */
        protected int markpos = -1;
    
        /**
         * The maximum read ahead allowed after a call to the
         * mark method before subsequent calls to the
         * reset method fail.
         * Whenever the difference between pos
         * and markpos exceeds marklimit,
         * then the  mark may be dropped by setting
         * markpos to -1.
         *
         * @see     java.io.BufferedInputStream#mark(int)
         * @see     java.io.BufferedInputStream#reset()
         */
        protected int marklimit;
    
        /**
         * Check to make sure that underlying input stream has not been
         * nulled out due to close; if not return it;
         */
        private InputStream getInIfOpen() throws IOException {
            InputStream input = in;
            if (input == null)
                throw new IOException("Stream closed");
            return input;
        }
    
        /**
         * Check to make sure that buffer has not been nulled out due to
         * close; if not return it;
         */
        private byte[] getBufIfOpen() throws IOException {
            byte[] buffer = buf;
            if (buffer == null)
                throw new IOException("Stream closed");
            return buffer;
        }
    
        /**
         * Creates a BufferedInputStream and saves its  argument, the input stream in, for later use. An internal buffer array is created and  stored in buf.
         * @param   in   the underlying input stream.
         */
        public BufferedInputStream(InputStream in) {
            this(in, DEFAULT_BUFFER_SIZE);
        }
    
        /**
         * Creates a BufferedInputStream with the specified buffer size, and saves its  argument, the input stream in, for later use.  An internal  buffer array of length  size is created and stored in buf.
         * @param   in     the underlying input stream.
         * @param   size   the buffer size.
         * @exception IllegalArgumentException if {@code size <= 0}.
         */
        public BufferedInputStream(InputStream in, int size) {
            super(in);
            if (size <= 0) {
                throw new IllegalArgumentException("Buffer size <= 0");
            }
            buf = new byte[size];
        }
    
        /**
         * Fills the buffer with more data, taking into account
         * shuffling and other tricks for dealing with marks.
         * Assumes that it is being called by a synchronized method.
         * This method also assumes that all data has already been read in,
         * hence pos > count.
         */
        private void fill() throws IOException {
            byte[] buffer = getBufIfOpen();
            if (markpos < 0)
                pos = 0;            /* no mark: throw away the buffer */
            else if (pos >= buffer.length)  /* no room left in buffer */
                if (markpos > 0) {  /* can throw away early part of the buffer */
                    int sz = pos - markpos;
                    System.arraycopy(buffer, markpos, buffer, 0, sz);
                    pos = sz;
                    markpos = 0;
                } else if (buffer.length >= marklimit) {
                    markpos = -1;   /* buffer got too big, invalidate mark */
                    pos = 0;        /* drop buffer contents */
                } else if (buffer.length >= MAX_BUFFER_SIZE) {
                    throw new OutOfMemoryError("Required array size too large");
                } else {            /* grow buffer */
                    int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
                            pos * 2 : MAX_BUFFER_SIZE;
                    if (nsz > marklimit)
                        nsz = marklimit;
                    byte nbuf[] = new byte[nsz];
                    System.arraycopy(buffer, 0, nbuf, 0, pos);
                    if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
                        // Can't replace buf if there was an async close.
                        // Note: This would need to be changed if fill()
                        // is ever made accessible to multiple threads.
                        // But for now, the only way CAS can fail is via close.
                        // assert buf == null;
                        throw new IOException("Stream closed");
                    }
                    buffer = nbuf;
                }
            count = pos;
            int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
            if (n > 0)
                count = n + pos;
        }
    
    
        public synchronized int read() throws IOException {
            if (pos >= count) {
                fill();
                if (pos >= count)
                    return -1;
            }
            return getBufIfOpen()[pos++] & 0xff;
        }
    
    
        private int read1(byte[] b, int off, int len) throws IOException {
            int avail = count - pos;
            if (avail <= 0) {
                /* If the requested length is at least as large as the buffer, and
                   if there is no mark/reset activity, do not bother to copy the
                   bytes into the local buffer.  In this way buffered streams will
                   cascade harmlessly. */
                if (len >= getBufIfOpen().length && markpos < 0) {
                    return getInIfOpen().read(b, off, len);
                }
                fill();
                avail = count - pos;
                if (avail <= 0) return -1;
            }
            int cnt = (avail < len) ? avail : len;
            System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
            pos += cnt;
            return cnt;
        }
    
    
        public synchronized int read(byte b[], int off, int len)
            throws IOException
        {
            getBufIfOpen(); // Check for closed stream
            if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
                throw new IndexOutOfBoundsException();
            } else if (len == 0) {
                return 0;
            }
    
            int n = 0;
            for (;;) {
                int nread = read1(b, off + n, len - n);
                if (nread <= 0)
                    return (n == 0) ? nread : n;
                n += nread;
                if (n >= len)
                    return n;
                // if not closed but no bytes available, return
                InputStream input = in;
                if (input != null && input.available() <= 0)
                    return n;
            }
        }
    
    
        public synchronized long skip(long n) throws IOException {
            getBufIfOpen(); // Check for closed stream
            if (n <= 0) {
                return 0;
            }
            long avail = count - pos;
    
            if (avail <= 0) {
                // If no mark position set then don't keep in buffer
                if (markpos <0)
                    return getInIfOpen().skip(n);
    
                // Fill in buffer to save bytes for reset
                fill();
                avail = count - pos;
                if (avail <= 0)
                    return 0;
            }
    
            long skipped = (avail < n) ? avail : n;
            pos += skipped;
            return skipped;
        }
    
    
        public synchronized int available() throws IOException {
            int n = count - pos;
            int avail = getInIfOpen().available();
            return n > (Integer.MAX_VALUE - avail)
                        ? Integer.MAX_VALUE
                        : n + avail;
        }
    
    
        public synchronized void mark(int readlimit) {
            marklimit = readlimit;
            markpos = pos;
        }
    
    
        public synchronized void reset() throws IOException {
            getBufIfOpen(); // Cause exception if closed
            if (markpos < 0)
                throw new IOException("Resetting to invalid mark");
            pos = markpos;
        }
    
    
        public boolean markSupported() {
            return true;
        }
    
    
        public void close() throws IOException {
            byte[] buffer;
            while ( (buffer = buf) != null) {
                if (bufUpdater.compareAndSet(this, buffer, null)) {
                    InputStream input = in;
                    in = null;
                    if (input != null)
                        input.close();
                    return;
                }
                // Else retry in case a new buf was CASed in fill()
            }
        }
    }
    BufferedInputSream

    1.1.5测试各种流在复制文件时的效率

    FileInputStream
    FileOutputStream
    基本字节流(节点流):
    一次读取一个字节;
    一次读取一个字节数组的数据

    BufferedInputStream
    BufferedOutputStream
    缓冲区流(包装流):
    一次读取一个字节;
    一次读取一个字节数组的数据

  • 相关阅读:
    推荐一个JavaScript触发器插件,可通过指定频次、指定时间内触发指定的处理函数
    TortoiseGit for windows安装与配置
    Postgresql 迁移随笔一
    三边定位 c#
    unset变量释放内存不起作用
    局域网下 连接别人的数据库授权
    iconv 参数详解
    urlencode()和rawurlencode()区别
    php数组函数
    php://input和parse_str()使用
  • 原文地址:https://www.cnblogs.com/wqbin/p/11176511.html
Copyright © 2011-2022 走看看