Java有两种不同的输入输出API,分别是IO(Input/Output)和NIO(New Input/Output)。虽然两者都提供了对文件和网络操作的支持,但在很多方面有很大不同。本文将从以下几个方面详细阐述两者的区别。
一、Java IO和NIO的整体区别
IO和NIO最重要的区别在于它们处理数据的方式和实现机制不同。Java IO是面向流的,数据流向一个固定的方向:即从源到目的地。数据可以从一个InputStream(输入流)读取,写入到一个OutputStream(输出流)。所有的传输或处理数据的单元都是一个字节。
NIO第一次引入了缓冲区的概念,以提高速度和效率。它提供了对通道(Channel)的支持,数据可以从通道读取到缓冲区中,或者从缓冲区写入到通道中。通道本身就是双向的,可以用于读写两个方向。此外,缓冲区允许用户使用内存映射文件(MappedByteBuffer)来读写文件,以便减少IO操作。
二、Java IO和NIO的基本类库不同
Java IO提供了InputStream、OutputStream、Reader和Writer等几个重要的类,可以实现从文件或网络流读取数据,或者向文件流或网络流写入数据。而NIO则提供了ByteBuffer、CharBuffer、ShortBuffer、IntBuffer、LongBuffer、FloatBuffer和DoubleBuffer等缓冲区,以便读写数据。它还提供了BufferedChannel、Selector、ServerSocketChannel和SocketChannel等操作缓冲区的类。
三、Java IO和NIO的阻塞和非阻塞机制不同
Java IO是阻塞的。即当IO操作时,程序会一直等待,直到数据已经可用才会继续执行下去。这意味着,一个线程在一个时间点只能读取或写入一个请求,不能同时处理多个请求。
NIO则提供了非阻塞I/O操作。基于NIO的操作可以大大提高处理请求的效率。非阻塞操作允许线程在等待请求完成时执行其他操作,从而使一个线程可以同时处理多个请求。
四、Java IO和NIO的多路复用机制不同
Java IO通过Socket类来实现TCP/IP网络通信。在Java IO中,线程必须等待请求I/O处理完成,这会导致线程的数量必须等于I/O请求的数量,从而开销巨大。
NIO则使用了基于选择器(Selector)的多路复用机制来避免为每个连接分配一个线程。这种机制是说,在一个线程中,可以通过选择器同时处理多个连接请求,并在每个请求就绪时进行处理。这可以轻松地让一个线程来管理多个连接,并显著减少线程的开销。
五、Java IO和NIO的扩展性差异
Java IO的线程模型不适合高并发的情况,因为线程开销很大,并且需要为每个连接分配一个线程。这会导致系统的性能受限。
NIO中的线程模型适合高并发请求。每个线程可以处理多个请求,从而保持了内存的稳定性。
六、应用实例——文件读取功能
下面我们就来看看Java IO和NIO在文件读取功能上的不同:
Java IO实现文件读取:
import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; public class FileReading { public static void main(String[] args) { File file = new File("test.txt"); try (FileReader fileReader = new FileReader(file); BufferedReader bufferedReader = new BufferedReader(fileReader)) { String line = null; while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } }
NIO实现文件读取:
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.stream.Stream; public class FileReadingNIO { public static void main(String[] args) { Path path = Paths.get("test.txt"); try (Streamlines = Files.lines(path)) { lines.forEach(System.out::println); } catch (IOException e) { e.printStackTrace(); } } }
七、小结
本文介绍了Java IO和NIO之间的不同之处,并且提供了一个应用实例,以便更好地理解它们的区别和使用场景。在选择使用API时,我们应该根据实际需求和情况,选择一个更适合我们的API。