您的位置:

Java IO 和 NIO的区别

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 (Stream lines = Files.lines(path)) {
            lines.forEach(System.out::println);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

  

七、小结

本文介绍了Java IO和NIO之间的不同之处,并且提供了一个应用实例,以便更好地理解它们的区别和使用场景。在选择使用API时,我们应该根据实际需求和情况,选择一个更适合我们的API。