Java的标准IO与新IO有什么区别

Java Standard IO vs New IO

Java 新输入/输出 (NIO)是随 JDK 1.4 引入的。从标准 IO 的角度出发,NIO 为 Java 库提供了高速、面向块的 IO。

通过定义类来保存数据,并通过在块中处理该数据,NIO 以一种java.io包无法使用的方式利用低级优化,而不使用本机代码。

在本文中,我们将重点确定标准 IO 与新 IO 之间最显着的差异,在决定在下一个项目中使用哪个之前,我们必须了解这些差异。

调用标准 IO
Java IO是指计算机与世界其他部分之间或单个程序与计算机其他部分之间的接口。

在 Java 编程中,IO 类直到最近才使用流比喻来实现。所有 IO 都被视为单个字节的移动,一次一个,通过名为 a 的对象Stream。

Stream IO 用于联系外界。它也在内部使用,用于将对象转换为字节,然后再转换为对象。它被称为序列化和反序列化。

介绍 Java 新 IO
Java NIO 的创建是为了让 Java 程序员无需编写自定义本机代码即可实现高速输入-输出操作。

NIO 将最耗时的 I/O 活动(即填充和排空缓冲区)移回操作系统,从而大大提高速度。

如果以上介绍让您感到口渴,请不要担心,随着我们的前进,您是否会感觉更好。让我们从找出差异开始。

IO 和 NIO 的区别
IO 流与 NIO 块
标准 IO 库 ( java.io.) 和新 IO ( java.nio.)之间最重要的区别在于数据如何打包并从源传输到目标。如前所述,标准 I/O 处理流中的数据,而 NIO 处理块中的数据。

甲面向流的I / O与数据系统处理的一个或多个字节一次。输入流产生一字节数据,输出流消耗一字节数据。为流数据创建过滤器非常容易。将几个过滤器链接在一起也相对简单,这样每个过滤器都可以在一个复杂的处理机制中发挥作用。

重要的是字节不会缓存在任何地方。此外,我们不能在流中的数据中来回移动。如果您需要在从流中读取的数据中来回移动,我们必须首先将其缓存在缓冲区中。

甲面向块的I / O系统涉及在块中的数据。每个操作在一个步骤中产生或消耗一个数据块。按块处理数据比按(流)字节处理数据快得多。您可以根据需要在缓冲区中前后移动。

数据块在处理过程中为我们提供了更多的灵活性。但是,我们还需要检查缓冲区是否包含我们需要的所有数据,以便完全处理它。并且,我们需要确保在将更多数据读入缓冲区时,我们不会覆盖尚未处理的缓冲区中的数据。

不利的一面是,面向块的 I/O 缺乏面向流 I/O 的一些优雅和简单。

阅读更多:使用 Java NIO 读取文件的 3 种方法

同步标准与异步新 IO
Java IO 的各种流都是阻塞的或同步的。这意味着,当一个线程调用read()orwrite()操作时,该线程被阻塞,直到有一些数据要读取,或者数据被完全写入。该线程将在此期间处于阻塞状态。这被认为是在现代语言中引入多线程的一个很好的充分理由。

在异步 IO 中,线程可以请求将某些数据写入通道,但不会等待它完全写入。然后该线程可以继续并同时执行其他操作。通常这些线程在没有被 IO 调用阻塞的时候将它们的空闲时间花在同时在其他通道上执行 IO 上。也就是说,单个线程现在可以管理多个输入和输出通道。

同步程序通常不得不求助于轮询,或者创建很多很多线程来处理大量连接。使用异步 I/O,您可以在任意数量的通道上监听 I/O 事件,无需轮询和额外线程。

异步 I/O 中的中心对象称为Selector。Selector 是您注册对各种 IO 事件感兴趣的地方,它是告诉您这些事件何时发生的对象。所以,我们需要做的第一件事就是创建一个 Selector。

Selector selector = Selector.open();
稍后,我们将register()在各种Channel对象上调用该方法,以注册我们对这些对象内部发生的 IO 事件的兴趣。的第一个参数register()始终是Selector。

阅读更多:如何在 Java NIO 中定义路径

Java IO 与 NIO API
不用猜测使用 NIO 时的 API 调用看起来与使用 IO 时的不同。在 NIO 中,不是仅仅从例如 an 中读取一个字节的数据字节,而是InputStream必须首先将数据读入 a Buffer,然后从其后进行处理。

使用标准 IO 读取文件的 Java 示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
>import java.io.BufferedReader;
>import java.io.FileReader;
>import java.io.IOException;

>public class WithoutNIOExample
>{
public static void main(String[] args)
{
BufferedReader br = null;
String sCurrentLine = null;
try
{
br = new BufferedReader(
new FileReader("test.txt"));
while ((sCurrentLine = br.readLine()) != null)
{
System.out.println(sCurrentLine);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
if (br != null)
br.close();
} catch (IOException ex)
{
ex.printStackTrace();
}
}
}
>}

使用 New IO 读取文件的 Java 示例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
>import java.io.IOException;
>import java.io.RandomAccessFile;
>import java.nio.ByteBuffer;
>import java.nio.channels.FileChannel;

>public class ReadFileWithFixedSizeBuffer
>{
public static void main(String[] args) throws IOException
{
RandomAccessFile aFile = new RandomAccessFile
("test.txt", "r");
FileChannel inChannel = aFile.getChannel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
while(inChannel.read(buffer) > 0)
{
buffer.flip();
for (int i = 0; i < buffer.limit(); i++)
{
System.out.print((char) buffer.get());
}
buffer.clear(); // do something with the data and clear/compact it.
}
inChannel.close();
aFile.close();
}
>}

结论
NIO 允许您仅使用单个(或更少)线程来管理多个通道,但代价是解析数据可能比使用标准 IO 从阻塞流中读取数据要复杂一些。

如果您需要同时管理数千个打开的连接,每个连接只发送少量数据,例如聊天服务器,在 NIO 中实现服务器可能是一个优势。同样,如果您需要与其他计算机保持大量开放连接,例如在 P2P 网络中,使用单个线程来管理所有出站连接可能是一个优势。

如果您的连接较少且带宽非常高,一次发送大量数据,则应该选择标准 IO 服务器实现。

本文翻译自:
https://howtodoinjava.com/java/io/difference-between-io-nio/