Java IO 过滤流 字节缓冲流 BufferedInput/OutputStream

Java IO 过滤流 字节缓冲流 BufferedInput/OutputStream

@author ixenos

概念



BufferedInput/OutputStream是实现缓存的过滤流,他们分别是FilterInput/OutputStream的子类。

BufferedInputStream工作流程



stream-->buf--read buf-->I

1.当一个BufferedInputStream被创建时,一个内部的缓冲区 byte[] buf = new byte[size] 也被建立,size默认是8192也就是默认创建一个8kb大小的缓存空间,BufferedInputStream预先在缓冲区存储来自连接输入流的数据

 1     private static int DEFAULT_BUFFER_SIZE = 8192;
 2     protected volatile byte buf[];
 3
 4     public BufferedInputStream(InputStream in) {
 5         this(in, DEFAULT_BUFFER_SIZE);
 6     }
 7
 8
 9     public BufferedInputStream(InputStream in, int size) {
10         super(in);
11         if (size <= 0) {
12             throw new IllegalArgumentException("Buffer size <= 0");
13         }
14         buf = new byte[size];
15     }

2.当BufferedInputStream的read方法被调用时,数据将从缓冲区中移出,而不是底层的输入流;

3.当BufferedInputStream缓冲区数据用完时,他自动从底层输入流中补充数据

  BufferedInputStream的read方法源码分析

 1     public synchronized int read() throws IOException {
 2         if (pos >= count) {
 3             fill();
 4             if (pos >= count)
 5                 return -1;
 6         }
 7         return getBufIfOpen()[pos++] & 0xff;
 8     }
 9
10     //getBufIfOpen对buf进行非空判断,然后返回buf值传递给buffer的一个byte[]数组
11     private byte[] getBufIfOpen() throws IOException {
12         byte[] buffer = buf;
13         if (buffer == null)
14             throw new IOException("Stream closed");
15         return buffer;
16     }

  BufferedInputStream的read(byte b[], int off, int len)源码分析

  1     //BufferedInputStream中的read进指定内存的方法
  2     public synchronized int read(byte b[], int off, int len)
  3         throws IOException
  4     {
  5         //缓冲流关闭时维护的buf消失,返回的buffer等于null,因为buf值传递给buffer,如下
  6         /*
  7            private byte[] getBufIfOpen() throws IOException {
  8                byte[] buffer = buf;
  9                if (buffer == null)
 10                    throw new IOException("Stream closed");
 11                return buffer;
 12            }
 13          */
 14         getBufIfOpen(); // Check for closed stream
 15         //范围判断
 16         if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
 17             throw new IndexOutOfBoundsException();
 18         } else if (len == 0) {
 19             return 0;
 20         }
 21
 22         int n = 0;
 23         //循环写数据到b,知道buffer数据不足返回-1,此时nread已累加记录
 24         for (;;) {
 25             int nread = read1(b, off + n, len - n);
 26             if (nread <= 0)
 27                 return (n == 0) ? nread : n;
 28             n += nread;
 29             //读完指定长度时返回
 30             if (n >= len)
 31                 return n;
 32             // if not closed but no bytes available, return
 33             //没读完指定长度,但缓冲区没数据时返回当前n
 34             InputStream input = in;
 35             if (input != null && input.available() <= 0)
 36                 return n;
 37         }
 38     }
 39
 40
 41     /**
 42      * read1方法是该read底层用来读取缓冲区buf的数据进指定数组的方法
 43      * 而fill方法又是read1方法中用来读取底层字节流到缓冲区buf的方法
 44      * 读取数据写进指定数组的一部分,必要时每次从底层流尽量读取数据
 45      */
 46     private int read1(byte[] b, int off, int len) throws IOException {
 47         int avail = count - pos;
 48         if (avail <= 0) {
 49             /* 如果所请求的长度至少和缓冲区一样大,并且
 50                 如果没有标记/复位活动,就没必要用缓冲区了,将直接从底层       流读取数据。以这种方式缓冲流将
 51                 级联无害
 52              */
 53             if (len >= getBufIfOpen().length && markpos < 0) {
 54                 //getInIfOpen返回的是经非空判断的底层流,所以调用的自然也是底层流的read方法,写进指定的内存b
 55                 return getInIfOpen().read(b, off, len);
 56             }
 57             //请求fill()方法来读取底层流数据
 58             fill();
 59             avail = count - pos;
 60             if (avail <= 0) return -1;
 61         }
 62         int cnt = (avail < len) ? avail : len;
 63         System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
 64         pos += cnt;
 65         return cnt;
 66     }
 67
 68
 69     //fill()方法填充空间,是底层用来读取流数据到缓冲区buf
 70     /**
 71      * Fills the buffer with more data, taking into account
 72      * shuffling and other tricks for dealing with marks.
 73      * Assumes that it is being called by a synchronized method.
 74      * This method also assumes that all data has already been read in,
 75      * hence pos > count.
 76      */
 77     private void fill() throws IOException {
 78         byte[] buffer = getBufIfOpen();
 79         //markpos是起始读取buffer的位置,pos是终点位置
 80         //起始小于零表明没有pos移动,从源码可知
 81         if (markpos < 0)
 82             pos = 0;            /* no mark: throw away the buffer */
 83         //当pos比buffer更长时
 84         else if (pos >= buffer.length)  /* no room left in buffer */
 85             //起始pos也有前移时
 86             if (markpos > 0) {  /* can throw away early part of the buffer */
 87                 int sz = pos - markpos;
 88                 System.arraycopy(buffer, markpos, buffer, 0, sz);
 89                 pos = sz;
 90                 markpos = 0;
 91              //buffer大小超过理论规模时
 92             } else if (buffer.length >= marklimit) {
 93                 markpos = -1;   /* buffer got too big, invalidate mark */
 94                 pos = 0;        /* drop buffer contents */
 95              //buffer大小超过本地VM内存限制时:MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8
 96             } else if (buffer.length >= MAX_BUFFER_SIZE) {
 97                 throw new OutOfMemoryError("Required array size too large");
 98             } else {            /* grow buffer */
 99                 int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
100                         pos * 2 : MAX_BUFFER_SIZE;
101                 if (nsz > marklimit)
102                     nsz = marklimit;
103                 byte nbuf[] = new byte[nsz];
104                 System.arraycopy(buffer, 0, nbuf, 0, pos);
105                 /*AtomicReferenceFieldUpdater是一个基于反射的工具类,
106                   它能对指定类的指定的volatile引用字段进行原子更新。
107                   (注意这个字段不能是private的) ,
108                   从源码知getBufIfOpen返回的是值传递的protected volatile byte buf[]
109                  */
110                 if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
111                     // Can‘t replace buf if there was an async close.
112                     // Note: This would need to be changed if fill()
113                     // is ever made accessible to multiple threads.
114                     // But for now, the only way CAS can fail is via close.
115                     // assert buf == null;
116                     throw new IOException("Stream closed");
117                 }
118                 buffer = nbuf;
119             }
120         //pos小于buf.length时,从底层流到缓冲区,使用InputStream的read(byte[])方法
121         count = pos;
122         int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
123         if (n > 0)
124             count = n + pos;
125     }
126     

BufferedOutputStream工作流程



I--write buf-->buf-->stream

1.BufferedOutputStream在内部缓冲区存储程序的输出数据,这样就不会每次调用write方法时,就把数据写到底层的输出流;

2.当BufferedOutputStream的内部缓冲区或者它被刷新(flush),数据一次性写到底层的输出流

时间: 2024-10-24 03:51:52

Java IO 过滤流 字节缓冲流 BufferedInput/OutputStream的相关文章

java的 IO流之缓冲流(转载)

java缓冲流本身不具IO功能,只是在别的流上加上缓冲提高效率,像是为别的流装上一种包装.当对文件或其他目标频繁读写或操作效率低,效能差.这时使用缓冲流能够更高效的读写信息.因为缓冲流先将数据缓存起来,然后一起写入或读取出来.所以说,缓冲流还是很重要的,在IO操作时记得加上缓冲流提升性能. 缓冲流分为字节和字符缓冲流 字节缓冲流为: BufferedInputStream-字节输入缓冲流 BufferedOutputStream-字节输出缓冲流 字符缓冲流为: BufferedReader-字符

【java的 IO流之缓冲流】

java缓冲流本身不具IO功能,只是在别的流上加上缓冲提高效率,像是为别的流装上一种包装.当对文件或其他目标频繁读写或操作效率低,效能差.这时使用缓冲流能够更高效的读写信息.因为缓冲流先将数据缓存起来,然后一起写入或读取出来.所以说,缓冲流还是很重要的,在IO操作时记得加上缓冲流提升性能. 缓冲流分为字节和字符缓冲流 字节缓冲流为: BufferedInputStream-字节输入缓冲流 BufferedOutputStream-字节输出缓冲流 字符缓冲流为: BufferedReader-字符

IO流之缓冲流

缓冲流 Java中提高了一套缓冲流,它的存在,可提高IO流的读写速度 缓冲流,根据流的分类字节缓冲流与字符缓冲流. 字节缓冲流 字节缓冲流根据流的方向,共有2个 l  写入数据到流中,字节缓冲输出流 BufferedOutputStream l  读取流中的数据,字节缓冲输入流 BufferedInputStream 它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度 字节缓冲输出流BufferedOutputStream 通过字节缓冲流,进行文件的读写操作 写数据到文件

IO流----转换流、缓冲流

打开一个文本文件,另存为: Ansi就是系统默认编码(就是gbk) 建一个编码是utf-8的txt文件, 例: import java.io.FileWriter; import java.io.IOException; public class Demo01 { public static void main(String[] args) throws IOException { //确定目的地 FileWriter fw=new FileWriter("E:\\zyx\\java\\utf-

Java转换流、缓冲流、流的操作规律和properties类整理

转换流 1.1                OutputStreamWriter类 OutputStreamWriter 是字符流通向字节流的桥梁:可使用指定的字符编码表,将要写入流中的字符编码成字节.它的作用的就是,将字符串按照指定的编码表转成字节,在使用字节流将这些字节写出去. package com.oracle.reader; public class Demo04 { public static void main(String[] args) throws IOException

转换流和缓冲流

1. 转换流(把字符流转成了字节流所以是桥梁):OutputStreamWriter;是字符输出流;先用FileOutputStream确定要写入的地址;然后再用转换流抓取要写入的地址和码表 2.InputStreamReader:是FileReader的父类并且是它的转换流 3.InputStreamReader和OutputStreamWriter的转换原理(字节流+码表) 4.字符转成字节后再写入:明确目的地:FileOutputStream fos=new FileOutputStrea

java字节缓冲流和字符缓冲流

一.字节缓冲流 1.介绍 字节缓冲流根据流的方向,分为: 1.写入数据到流中,字节缓冲输出流 BufferedOutputStream 2.读取流中的数据,字节缓冲输入流 BufferedInputStream 它们的内部都包含了一个缓冲区,通过缓冲区读写,就可以提高了IO流的读写速度 2.字节缓冲输出流BufferedOutputStream 构造方法: public BufferedOutputStream(OutputStream out):创建一个新的缓冲输出流,以将数据写入指定的底层输

java _io_字节缓冲流(装饰器)输入、输出

*装饰模式 字节缓冲流 BufferedInputStream bis=new BufferedInputStream(inputStream is) BufferedOutputStream bos=new BufferedOutputStream(OutputStream os) 最底层一定是节点流 只需要释放最外层的处理流,若要手动关闭遵循从里到外的顺序关闭(从字节流到处理流) 默认为8k,可以改变//参数是字节输入流对象InputStream is =new BufferedInputS

字节缓冲流 ( BufferedInputStream / BufferedOutputStream)

package com.sxt.reader; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; /* * 字节缓冲流 * BufferedI