`

Java I/O关于缓冲区部分提高性能的源码分析【Stream】

阅读更多
拿FileInputStream来举例:
class FileInputStream extends InputStream


从顶级的InputStream开始

InputStream 定义了3个read方法。
read();
read(byte[]);
read(byte[],int off,int len);

第二个read(byte[])其实就是read(b, 0, b.length) ,所以等同于第三个;

第一个read()方法,api介绍如下:
引用
从输入流中读取数据的下一个字节。返回 0 到 255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。
子类必须提供此方法的一个实现。


第三个read()方法,api介绍如下:
引用
将输入流中最多 len 个数据字节读入 byte 数组。尝试读取 len 个字节,但读取的字节也可能小于该值。以整数形式返回实际读取的字节数。
在输入数据可用、检测到流末尾或者抛出异常前,此方法一直阻塞。

如果 len 为 0,则不读取任何字节并返回 0;否则,尝试读取至少一个字节。如果因为流位于文件末尾而没有可用的字节,则返回值 -1;否则,至少读取一个字节并将其存储在 b 中。

将读取的第一个字节存储在元素 b[off] 中,下一个存储在 b[off+1] 中,依次类推。读取的字节数最多等于 len。设 k 为实际读取的字节数;这些字节将存储在 b[off] 到 b[off+k-1] 的元素中,不影响 b[off+k] 到 b[off+len-1] 的元素。

在任何情况下,b[0] 到 b[off] 的元素以及 b[off+len] 到 b[b.length-1] 的元素都不会受到影响。

类 InputStream 的 read(b, off, len) 方法重复调用方法 read()。如果第一次这样的调用导致 IOException,则从对 read(b, off, len) 方法的调用中返回该异常。如果对 read() 的任何后续调用导致 IOException,则捕获该异常并将其视为到达文件末尾;到达该点时读取的字节存储在 b 中,并返回发生异常之前读取的字节数。在已读取输入数据 len 的请求数量、检测到文件结束标记、抛出异常前,此方法的默认实现将一直阻塞。建议子类提供此方法更为有效的实现。


关于三段红字的注解:
第一段:InputStream是所有输入流的顶级类,当然只定义,不实现,具体的由子类去实现,如AudioInputStream, ByteArrayInputStream, FileInputStream等。
第二段:指明了InputStream的read(byte[],int off,int len)的实现方式,就是简单的调用read()方法而已,而read()方法是一次只读取一个字节,依然每次都要调用底层系统,所以InputStream的read(byte[],int off,int len)性能和直接调用read()一样,byte[]缓冲区在这是摆设。
第三段:正是由于第二段所说,才建议子类提供性能更好的方式来覆盖read(byte[],int off,int len)方法。

那InputStream的子类有哪些呢?看下API就知道了,这几只拿FileInputStream来说.
下面是FileInputStream的部分源码:
 public native int read() throws IOException;

 private native int readBytes(byte b[], int off, int len) throws IOException;

 public int read(byte b[]) throws IOException {
	return readBytes(b, 0, b.length);
    }

 public int read(byte b[], int off, int len) throws IOException {
	return readBytes(b, off, len);
    }

这里两个read()方法都是用本地方法实现,因为FileInputStream是跟底层的操作系统交互的,没有比用本地方法来实现的性能更好,更容易的了。所以这里就采用了第三段里的建议,真正实现了缓存的功能,虽然我们并不知道如何实现的。

那么既然FileInputStream已经实现了缓存来提高性能,那么BufferedInputStream又拿来干嘛?
先看api介绍:
引用
BufferedInputStream 为另一个输入流添加一些功能,即缓冲输入以及支持 mark 和 reset 方法的能力。在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。在读取或跳过流中的字节时,可根据需要从包含的输入流再次填充该内部缓冲区,一次填充多个字节。mark 操作记录输入流中的某个点,reset 操作使得在从包含的输入流中获取新字节之前,再次读取自最后一次 mark 操作后读取的所有字节。


其实上面所说的“缓冲输入”并不是真正的像FileInputStream那样用本地方法来提高性能,而是指在这基础上,为了程序员操作方便,内部提供了一个缓冲区(byte[1024*8] buf),并装饰了FileInputStream类(构造BufferedInputStram时必须提供被装饰的InputStream就可看出)。
当用FileInputStream的时候,read()是从底层读一个字节,read(byte[],int off,int len)则是一次性读取了len-off个字节,我们需提供一个byte[]来存放,
而用BufferedInputStream的时候,其read()其实和read(byte[],int off,int len)一样,内部都是调用构造输入的FileInputStream的read(byte[],int off,int len)方法,将底层数据读入到byte[]里,而且byte[]不需要我们来提供,类本身定义了一个byte[] buf数组来存放这些数据,所以,如果使用BufferedInputStream我们的程序又不需要对byte[]数组操作的话,直接这样写就行了:
FileInputStream fis=new FileInputStream("d:\\a.txt");
BufferedInputStream bis=new BufferedInputStream(fis);
int data=0;
while((data=bis.read())!=-1){
	//......		
}

这样虽然也是一次读一个字节,但不是每次都从底层读取数据,而是一次调用底层系统读取了最多buf.length个字节到buf数组中,然后从buf中一次读一个字节,减少了频繁调用底层接口的开销。
等同于
FileInputStream fis=new FileInputStream("d:\\a.txt");
byte[] mybuff=new byte[1024];
int count=0;
while((count=fis.read(mybuff))!=-1){
     //......
}


如果是用BufferedInputStream的read(byte[],int off,int len)那缓冲区则由传入的byte[]来充当(虽然内部其实有时候还用到了buf,但表现出来的就是用传入的byte[]来缓冲)。

讲了这么多,那如果要缓冲那该用FileInputStream还是BufferedInputStream呢?回到上面紫色的文字,BufferedInputStream主要不是提供buf,而是封装了缓冲和标记/回读的功能。如果你既不用到标记/回读功能,又不要操作中间的缓冲数组,那显而易见直接用FileInputStream的read(byte[],int off,int len)是效率最高的。

最后说下为什么用缓冲性能就更好,因为应用程序可以将多个字节写入底层输出流中(native read(byte)),而不必针对每个字节写入都调用底层系统(native read())。OutputStream原理基本差不多,这里就不说了。

3
0
分享到:
评论

相关推荐

    Java I/O 过滤流-带格式的读写操作

    - **BufferedReader** 和 **BufferedWriter**:为了提高效率,Java提供了缓冲流,它们在内部维护了一个缓冲区,可以一次性处理大量数据,减少系统调用的次数。 4. **示例代码** - `DataTest.java`:可能包含了...

    Java I/O层次结构详解

    - **java.nio包**:引入了通道(Channel)和缓冲区(Buffer)的概念,提供异步I/O操作。 - **Selector**:用于多路复用,监控多个通道的事件。 12. **工具类** - **PrintStream**:方便地打印各种类型的数据,...

    《Java语言程序设计》课件及源代码_第6章 输入输出流

    7. **I/O多路复用**:虽然题目中没有明确提及,但在更高级的I/O编程中,Java提供了`java.nio`包,支持非阻塞I/O和选择器,允许同时处理多个输入/输出通道,提高性能。 以上内容只是基于提供的文件名的推测,实际...

    mldn nio ppt 源码

    《深入理解Java NIO:基于mldn nio ppt源码解析》 Java NIO(Non-blocking Input/Output,非阻塞I/O)是Java在JDK 1.4引入的一...同时,源码分析也有助于我们解决实际开发中遇到的I/O问题,更好地优化系统资源的使用。

    java源码:Java文件切割器源代码.rar

    文件切割的基础是Java的I/O流(Input/Output Stream)机制。Java提供了多种类型的输入输出流,包括字节流和字符流,用于读写文件。在这个源码中,开发者可能使用了`FileInputStream`和`FileOutputStream`来读取和...

    《JAVA 核心技术 卷I:基础知识》源码

    - NIO(非阻塞I/O):适用于高性能网络应用,源码将展示通道、缓冲区等NIO组件的使用。 7. **多线程**: - 线程创建:通过Thread类或Runnable接口创建线程。 - 线程同步:synchronized关键字,wait(),notify()...

    Android读取Txt文件源码及性能分析

    1. 使用缓冲区:通过调整`BufferedReader`的缓冲大小,可以减少磁盘I/O次数,从而提高读取速度。 2. 异步读取:避免在主线程上执行耗时操作,而是使用AsyncTask或其他异步机制,以免阻塞用户界面。 3. 分块处理:...

    Project7_学生信息_源码

    通常,我们会在它们之上添加缓冲区(如BufferedInputStream或BufferedOutputStream),以提高性能。 3. 文件对象和路径 在处理文件时,需要创建File对象,它表示文件或目录的路径。File对象提供了很多方法,如...

    java_file

    除了基本的文件操作,Java还提供了NIO(Non-blocking I/O)框架,位于`java.nio`包下,提供了通道(Channel)和缓冲区(Buffer)的概念,使得非阻塞I/O成为可能,尤其在处理大量并发I/O请求时更为高效。 在源码分析...

    java 文件夹浏览器

    - `java.nio`包引入了通道(Channels)和缓冲区(Buffers)的概念,如`FileChannel`用于文件操作,`SocketChannel`用于网络通信。 - `Selector`类允许单线程处理多个通道,实现非阻塞I/O。 - `Files`类提供了很多...

    Java CSV批量导出工具类

    此外,源码可能包含了一些特定的优化技巧,如缓冲区大小的调整、线程同步机制等,这些都是提高性能的关键。 5. **性能优化**:在处理大数据时,除了分批和多线程,还有其他性能优化策略。例如,使用内存映射文件...

    简单java音乐播放器源码

    DataLine接口是所有音频输出设备的基类,它管理音频数据的缓冲区和播放控制。通过实现这两个接口,可以实现音频的播放、停止、暂停等操作。 6. Swing组件: 在Java GUI中,常常使用Swing库来创建用户界面。音乐...

    学习资料

    - **流(Stream)**:在Java I/O中,数据被看作是在流中流动的。流是数据传输的抽象表示,可以是字符流(处理字符数据)或字节流(处理二进制数据)。 - **节点流(Node Stream)**:直接连接到数据源或目的地的流...

    (源码下载)jdk6.0从入门到精通-----chapter2--输入输出,克隆对象

    Java的I/O系统基于流的概念,它将所有数据源(如文件、网络连接或内存缓冲区)视为流。流可以分为字符流(处理字符数据)和字节流(处理二进制数据),进一步又分为输入流和输出流。 1. **字节流**:`InputStream`...

    字符串缓冲区

    在编程领域,字符串缓冲区是一个重要的概念,尤其是在处理大量字符串操作时,它的存在极大地提高了程序的性能和效率。本文将深入探讨字符串缓冲区的工作原理、优势以及如何在不同编程语言中使用它。 字符串缓冲区,...

    java编写的播放器,附源码

    7. **缓冲区管理**:为了提高播放性能,音频数据通常会被加载到内存缓冲区中。如何合理设置缓冲区大小,以及如何管理缓冲区以避免数据丢失或延迟,是实现流畅播放的关键。 8. **第三方库**:虽然Java Sound API功能...

    NIO.rar_NIO_java nio

    而NIO引入了通道(Channel)和缓冲区(Buffer)的概念,并支持非阻塞I/O操作,使得数据可以从通道直接读入到缓冲区,或者从缓冲区直接写入到通道,实现了双向数据传输,并且可以同时处理多个连接。 在这个"NIO.rar_NIO_...

    JAVA核心技术第九版I II 卷SUN公司 英文原版

    1. **IO与NIO**:深入分析传统IO流和非阻塞IO(NIO)的原理及使用,包括缓冲区、选择器等。 2. **网络编程**:讲解Socket编程,包括TCP和UDP通信,以及URL和URLConnection的使用。 3. **反射**:介绍反射机制,...

    java音乐播放器源代码

    通过分析和学习这个Java音乐播放器的源代码,你可以深入了解Java的多媒体编程,提高自己的编程技巧,并为将来开发更复杂的音频应用打下坚实的基础。此外,这个项目还可以作为一个实战练习,让你在实际操作中巩固理论...

    java面试大全

    5. **IO与NIO**:Java的IO流体系和非阻塞I/O模型NIO(New IO)是处理输入输出的关键,理解缓冲区、通道、选择器等概念,能够优化程序的读写效率。 6. **设计模式**:设计模式是解决软件设计中常见问题的模板,如...

Global site tag (gtag.js) - Google Analytics