`
haitaoandroid
  • 浏览: 27457 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

Java IO与NIO的相关问题

 
阅读更多

  流(Stream)是最早的Java对IO的抽象,而通道(Channel)是NIO对新Java对IO的抽象,通道与流的不同之处在于通道是双向的。而流只是在一个方向上移动(一个流必须是InputStream或者OutputStream的子类), 而通道可以用于读、写或者同时用于读写。流和通道的基本单位都是字节,但是流是以字节数组作为缓冲区中介,而通道是以ByteBuffer来作为缓冲区中介。

流中包含的字节如流水一样,一旦流过去,就无法再使用。但由于流的实现是抽象类,在其子类中可以选择覆写父类的某些操作,所以子类输入输出流可能会有额外的控制操作,以便实现流的部分内容的重新读取,如流的标记(mark)和重置功能(reset),但并不是每一种流都有这两种功能,需要有相应的实现,可通过markSupported方法来判断是否支持标记功能。因为流无法复用,假如有一个流有多个接收者,那怎么办?上面介绍的标记和重置功能是其中一个方法,也可以把流中的全部数据保存到一个字节数组中,在不同的接受着中数据传递是通过这个字节数组来完成,而不是使用流的对象。其中流的标记和重置功能也是通过第二种方法实现的,只是这个字节数组的保存和操作是又流的某些子类来实现,如BufferedInputStream类。

 调用流的read方法时,如果没有足够的数据可以用,则read方法会被阻塞,直到当前的流成功的完成准备为止。从流中读取的数据并不是马上进入目的介质,而是先放入字节数组等缓冲区,等合适的时机再执行实际的写入操作。当然可以通过调用flush方法强制写入,注意在缓冲区满或者流关闭的时候,也会自动执行实际的写入操作。

  字节流是处理字节的,Java IO还有一种处理字符的字符流,即java.io.Reader类和java.io.Writer类及其子类,字符类一般是通过字节流InputStream类和OutputStream类来创建,对应的是InputStreamReader类和OutputStreamWriter类,只要指定编码格式就行了。

Java NIO的通道使用的基本缓冲区是ByteBuffer,其中有3个基本状态变量:容量(capacity),就是缓冲区的大小;读写限制(limit),总大小中允许读写的最大位置;读写位置(position),当前读写的位置。这三个状态变量都是以字节为单位的,假如是CharBuffer,则是以字符为单位,IntBuffer则是以整数为单位,等等。
ByteBuffer的基本方法: clear,把读写限制设为缓冲区的容量,同时把读写位置设为0,flip方法,把读写限制设为当前的读写位置,同时把读写位置设为0,rewind方法,不改变读写限制,仅把读写位置设为0,compact方法,把当前读写位置到读写限制范围内的数据复制到内部存储空间的最前面,然后再把读写位置移动到紧接着复制完成的数据的下一个位置,读写限制设置为容量的大小。ByteBuffer的实现可分为直接缓冲区和非直接缓冲区,直接缓冲区直接使用操作系统底层的IO操作来完成,提升了读写操作时的性能,不过也带来了额外的创建和销毁时的代价,直接缓冲区一般是常驻内存,会增加内存开销,一般用在对性能较高的情况。以下通过三个简单的例子来理解流和通道对文件复制的操作。
        //使用流来实现文件的复制
	 public static void copyFileByStream(String src,String dest) throws IOException{
		 FileInputStream in=new FileInputStream(src);
	        File file=new File(dest);
	        if(!file.exists())
	            file.createNewFile();
	        FileOutputStream out=new FileOutputStream(file);
	        int c;
	        byte buffer[]=new byte[1024];  //每次读取的字节数
	        while((c=in.read(buffer))!=-1){
	                out.write(buffer);        
	        }
	        in.close();
	        out.close();
	    }
	 //使用ByteBuffer作为缓冲区来实现文件的复制
	 public static void copyFileByByteBuffer(String src,String dest)  throws IOException{
	        ByteBuffer buffer = ByteBuffer.allocateDirect(32*1024);//分配ByteBuffer的容量大小
	        FileInputStream in=new FileInputStream(src);
	        FileOutputStream out=new FileOutputStream(dest);
			FileChannel s = in.getChannel();
			FileChannel d = out.getChannel();  
			while(s.read(buffer)>0||buffer.position()!=0){ //通过在通道上使用ByteBuffer来传输,不需要记录每次实际读取的字节数
					buffer.flip();
					d.write(buffer);
					buffer.compact();
				}
		
	    }
	 
	 //使用通道的传输方法来实现文件的复制
	 public static void copyFileByChannelTransfer(String src,String dest)  throws IOException{
	        ByteBuffer buffer = ByteBuffer.allocateDirect(32*1024);
	        FileInputStream in=new FileInputStream(src);
	        FileOutputStream out=new FileOutputStream(dest);
			FileChannel s = in.getChannel();
			FileChannel d = out.getChannel();
			s.transferTo(0, s.size(), d);//直接从一个通道传输到另一个通道。
			
	    }
由以上可以看出,使用ByteBuffer类不需要像流一样记录每次实际读取的字节数,只要分配一个固定大小的ByteBuffer缓冲区就行了,文件通道的transferTo方法使得数据传输更加简单。
对大文件的操作一般使用ByteBuffer的子类MappedByteBuffer,该类将系统的内存地址映射到要操作的文件上,操作这些内存地址就相当于读取文件的内容,这样就大大提高了操作文件的性能。具体用法看相关文档。
FileChannel类还有lock和tryLock方法可对文件进行加锁,但是该加锁是在虚拟机级别的,对于虚拟机上的多线程程序,不能用这种加锁机制来协同不同的线程对文件的访问。FileChannel类的加锁是应用程序与应用程序之间的加锁。
由于传统的Socket类和ServerSocket类中提供的与建立连接和数据传输相关的方法都是阻塞式的,套接字通道提供了非阻塞式的和多路复用的套接字连接。多路复用套接字需要通过一个选择器(Selector)来对所有的套接字通道进行管理监听,当其中的某些套接字通道上有Selector感兴趣的事件发生的时候,这个通道就会变成可用的状态,然后可以进行各种通道操作。不过需要在一开始的时候把我们需要监听的套接字通道注册到选择器(Selector)上,以表明我们需要由选择器来监听这个套接字通道。
网上有一比较好的隐喻可以说明套接字的阻塞和非阻塞方法,摘抄如下:

一辆从A开往B的公共汽车上,路上有很多点可能会有人下车。司机不知道哪些点会有哪些人会下车,对于需要下车的人,如何处理更好?

1.司机过程中定时询问每个乘客是否到达目的地,若有人说到了,那么司机停车,乘客下车。(类似阻塞式)

2.每个人(相当于套接字通道)告诉售票员(相当于Selector)自己的目的地(相当于套接字的事件),然后睡觉,司机(相当于CPU)只和售票员交互,到了某个点由售票员通知乘客下车。(类似非阻塞),很显然,每个人要到达某个目的地可以认为是一个线程,司机可以认为是CPU。在阻塞式里面,每个线程需要不断的轮询,上下文切换,以达到找到目的地的结果。而在非阻塞方式里,每个乘客(线程)都在睡觉(休眠),只在真正外部环境准备好了才唤醒,这样的唤醒肯定不会阻塞。




参考:《深入理解Java7》成富

分享到:
评论

相关推荐

    Java IO_NIO

    然而,传统的IO模型在处理大量并发连接时表现出效率较低的问题,为了解决这个问题,Java引入了NIO(Non-blocking Input/Output)模型。 **Java IO核心概念** Java IO的核心类包括InputStream、OutputStream、Reader...

    Java IO与NIO文档

    Java IO与NIO是Java平台中用于处理输入输出操作的核心技术。它们在处理数据传输、文件操作、网络通信等方面起着至关重要的作用。本篇将深入探讨这两个领域,旨在帮助开发者更好地理解和应用这些概念。 首先,Java ...

    java io 与java nio区别

    ### Java IO 与 Java NIO 的区别 在深入探讨Java IO与Java NIO之间的区别之前,我们先简单回顾一下这两种I/O模型的基本概念。 #### 1. Java IO(Blocking IO) Java IO,也称为传统的阻塞式IO或同步阻塞式IO,是...

    JAVA IO and NIO

    在IntelliJ IDEA中,开发者可以方便地使用Java IO和NIO编写和测试相关的代码。IDE提供了强大的代码补全、调试和测试工具,使得开发过程更加高效。对于Java IO,IntelliJ IDEA会自动处理流的关闭,对于NIO,它也提供...

    Java IO NIO and NIO 2 无水印pdf

    Java IO NIO and NIO 2 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn...

    java学习笔记1(java io/nio)

    java学习笔记1(java io/nio)设计模式

    Java IO NIO and NIO 2 epub

    Java IO NIO and NIO 2 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

    Java IO,NIO and NIO.2 mobi

    java io nio nio2 java io的百科全书 mobi格式 需要kindle 软件

    Java IO与NIO:深入理解与实践指南

    Java IO和NIO提供了两种不同的I/O处理方式,各有优势和适用场景。IO适用于简单的I/O操作,而NIO则适合于需要高性能和高并发的应用。了解这两种I/O处理方式的区别和特点,可以帮助开发者根据具体的应用需求选择合适的...

    java IO NIO AIO.xmind

    涉及到java io, nio, aio相关知识点,学习过程中的一些总结,持续更新中,xmind 格式

    JavaIO和NIO练习

    在"JavaIODemo"这个练习中,我们可能会看到以下内容: 1. 流的创建与使用:演示如何创建输入流和输出流对象,例如从文件读取数据并写入到另一个文件。 2. 缓冲技术:使用BufferedReader和BufferedWriter实现高效的...

    java IO、NIO、AIO详解.docx

    Java IO、NIO、AIO 详解 Java IO、NIO、AIO 是 Java 语言中三种不同的输入/输出机制,分别对应着不同的编程模型和设计理念。在高并发环境中,选择合适的输入/输出机制非常重要,本文将对 Java IO、NIO、AIO 进行...

    JAVA IO-NIO 详解

    Java的IO与NIO是程序与外部环境交互的基础,它们各自具有独特的优势和应用场景。传统IO适用于简单且低并发的场景,而NIO则更适合高并发、高性能的应用。通过深入理解Channel、Buffer和Selector等核心组件的工作原理...

    IO和NIO区别

    Java 中的 IO 和 NIO 是两个不同的输入/输出机制,它们之间有许多区别。下面我们将详细讲解 IO 和 NIO 的区别。 1. 数据处理方式 标准 IO 以流的方式处理数据,也就是说数据是以流的形式传输的,而 NIO 则以块的...

    SimpleSocketServer:Java IO | NIO样本

    SimpleSocketServer Java IO | NIO样本使用Java IO和NIO设置自己的Socket Server(待办事项) 深入了解Tomcat和Jetty的实现方式(希望如此)

    java nio与io性能测试

    本文将深入探讨Java NIO与IO的性能测试,并通过代码实例来展示它们之间的差异。 首先,我们来看传统的Java IO模型。IO模型基于流,数据是从输入流到输出流的单向传输。例如,`FileInputStream`和`FileOutputStream`...

    Java IO, NIO and NIO.2(Apress,2015)

    Java I/O, NIO, and NIO.2 is a power-packed book that accelerates your mastery of Java's various I/O APIs. In this book, you'll learn about classic I/O APIs (File, RandomAccessFile, the stream classes ...

Global site tag (gtag.js) - Google Analytics