Java NIO 开发

简介: 本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。

Java NIO 新篇介绍加示例代码

Java NIO(New IO)是 JDK 1.4 引入的一组新的 I/O API,用于支持非阻塞式 I/O 操作。相比传统的 Java IO API,NIO 提供了更快、更灵活的 I/O 操作方式,可以用于构建高性能网络应用程序。

Java NIO 的主要组成部分包括:

Channel:通道是一个在应用程序和文件、网络套接字之间的连接。可以通过通道来进行数据的读取和写入。 Buffer:缓冲区是一个容器,用于存储数据。在 NIO 中,所有的数据读取和写入都是通过缓冲区进行的。 Selector:选择器用于监听多个 NIO 通道的事件,如读写事件。当某个通道发生事件时,选择器会通知该事件并对其进行处理。 相比传统的 Java IO,Java NIO 的优点包括:

非阻塞模式:NIO 可以使用非阻塞模式进行网络编程,使程序不必等待网络操作完成才能进行其他操作,提高了程序的响应速度。 多路复用:一个线程可以同时处理多个 NIO 通道,减少了线程的开销和资源占用。 缓冲区操作:NIO 使用缓冲区进行数据读取和写入,可以提高数据访问速度。 下面是 Java NIO 常用类和接口:

Channel:提供了各种类型的通道接口,如 FileChannel、DatagramChannel、SocketChannel 和 ServerSocketChannel 等。 Buffer:提供了各种类型的缓冲区实现,如 ByteBuffer、CharBuffer、ShortBuffer 和 DoubleBuffer 等。 Selector:提供了 Selector 接口,用于监听多个通道的事件,可以使用一个线程处理多个通道。 总之,Java NIO 提高了网络编程的效率和性能,使得程序可以处理更多并发请求。但同时需要注意 NIO 的复杂性和学习难度,需要仔细理解其原理和使用规范。

我在早期有讲过Java NIO的基本用法 如果初学者可以 浏览 早期的Java NIO 文章

一,Channel实现类

Channel实现类 讲解

在Java NIO中,Channel是一个重要的概念,它代表着一个可以进行读写操作的实体,可以与文件、网络套接字等进行交互。

Java NIO提供了多种不同类型的Channel实现类,下面是其中一些常用的实现类:

  1. FileChannel:用于读写文件数据的通道,可以从文件中读取数据到缓冲区,也可以将缓冲区中的数据写入文件。 FileChannel类是Java NIO中用于对文件进行读写操作的通道。它提供了一系列方法来实现文件的读取和写入操作。以下是FileChannel类中常用的方法:
  1. open(Path path, OpenOption... options):静态方法,用于打开一个文件通道。参数path表示文件路径,options表示打开文件的选项,例如StandardOpenOption.READ表示以只读方式打开文件,StandardOpenOption.WRITE表示以写入方式打开文件等。
  2. read(ByteBuffer dst):从通道中读取数据到指定的缓冲区。返回值为读取的字节数,如果返回-1表示已经读取到文件末尾。
  3. write(ByteBuffer src):将指定的缓冲区中的数据写入到通道中。返回值为写入的字节数。
  4. position()position(long newPosition):获取或设置当前通道的位置。position()方法返回当前位置,position(long newPosition)方法将位置设置为指定的值。
  5. size():获取通道关联文件的大小。
  6. truncate(long size):将通道关联文件截断为指定的大小。
  7. force(boolean metaData):强制将通道关联文件的内容刷新到磁盘上。
  8. transferTo(long position, long count, WritableByteChannel target)transferFrom(ReadableByteChannel src, long position, long count):这两个方法用于在通道之间直接传输数据,可以避免数据的中间复制。
  9. lock()tryLock():用于对通道进行加锁操作,实现文件的独占访问。
  10. close():关闭通道。

以上是FileChannel类中的一些常用方法,通过这些方法可以实现对文件的读写操作。需要注意的是,在使用FileChannel进行读写操作时,通常需要结合ByteBuffer类来完成数据的读取和写入。

  1. SocketChannel:用于进行TCP连接的通道,可以通过SocketChannel与远程服务器建立连接,并进行数据的读写操作。 SocketChannel是Java NIO中用于进行TCP连接的通道,它提供了一系列方法来实现网络数据的读取和写入操作。以下是SocketChannel类中常用的方法:
  1. open():静态方法,用于打开一个SocketChannel。
  2. connect(SocketAddress remote):连接到指定的远程服务器。参数remote表示远程服务器的地址。
  3. finishConnect():完成连接操作。在调用connect()方法后,需要调用finishConnect()方法等待连接完成。
  4. read(ByteBuffer dst):从通道中读取数据到指定的缓冲区。返回值为读取的字节数,如果返回-1表示已经读取到流的末尾。
  5. write(ByteBuffer src):将指定的缓冲区中的数据写入到通道中。返回值为写入的字节数。
  6. isOpen():判断通道是否处于打开状态。
  7. isConnected():判断是否已经连接到远程服务器。
  8. socket():获取与此通道关联的套接字。
  9. getRemoteAddress()getLocalAddress():分别获取远程和本地的地址。
  10. setOption(SocketOption<T> name, T value)getOption(SocketOption<T> name):用于设置和获取套接字选项。
  11. configureBlocking(boolean block):设置通道的阻塞模式。如果block为true,表示通道为阻塞模式,否则为非阻塞模式。
  12. register(Selector sel, int ops):将通道注册到指定的选择器中,以便进行选择操作。
  13. close():关闭通道。

以上是SocketChannel类中的一些常用方法,通过这些方法可以实现网络数据的读取和写入操作。需要注意的是,在使用SocketChannel进行读写操作时,通常需要结合ByteBuffer类来完成数据的读取和写入。

  1. ServerSocketChannel:用于监听TCP连接请求的通道,可以通过ServerSocketChannel监听特定的端口,并等待客户端的连接请求。

ServerSocketChannel是Java NIO中用于创建服务器端的通道,它提供了一系列方法来实现服务器的监听和接收客户端连接。以下是ServerSocketChannel类中常用的方法:

  1. open():静态方法,用于打开一个ServerSocketChannel。
  2. bind(SocketAddress local):绑定服务器的本地地址。参数local表示本地地址。
  3. accept():接受客户端的连接请求,并返回一个SocketChannel用于与客户端进行通信。
  4. configureBlocking(boolean block):设置通道的阻塞模式。如果block为true,表示通道为阻塞模式,否则为非阻塞模式。
  5. isOpen():判断通道是否处于打开状态。
  6. socket():获取与此通道关联的服务器套接字。
  7. getLocalAddress():获取服务器绑定的本地地址。
  8. setOption(SocketOption<T> name, T value)getOption(SocketOption<T> name):用于设置和获取套接字选项。
  9. register(Selector sel, int ops):将通道注册到指定的选择器中,以便进行选择操作。
  10. close():关闭通道。

以上是ServerSocketChannel类中的一些常用方法,通过这些方法可以实现服务器的监听和接受客户端连接。需要注意的是,在使用ServerSocketChannel时,通常需要结合SocketChannel来与客户端进行通信。

  1. DatagramChannel:用于进行UDP连接的通道,可以通过DatagramChannel发送和接收UDP数据包。 DatagramChannel是Java NIO中用于进行UDP通信的通道,它提供了一系列方法来实现数据的发送和接收。以下是DatagramChannel类中常用的方法:
  1. open():静态方法,用于打开一个DatagramChannel。
  2. bind(SocketAddress local):将通道绑定到指定的本地地址。参数local表示本地地址。
  3. receive(ByteBuffer dst):从通道中接收数据,并将数据存储到指定的缓冲区中。返回值为接收的字节数,如果返回-1表示没有数据可读。
  4. send(ByteBuffer src, SocketAddress target):将指定的缓冲区中的数据发送到目标地址。参数src表示要发送的数据,target表示目标地址。
  5. configureBlocking(boolean block):设置通道的阻塞模式。如果block为true,表示通道为阻塞模式,否则为非阻塞模式。
  6. isOpen():判断通道是否处于打开状态。
  7. socket():获取与此通道关联的套接字。
  8. getLocalAddress():获取通道绑定的本地地址。
  9. setOption(SocketOption<T> name, T value)getOption(SocketOption<T> name):用于设置和获取套接字选项。
  10. close():关闭通道。

以上是DatagramChannel类中的一些常用方法,通过这些方法可以实现UDP数据的发送和接收。需要注意的是,在使用DatagramChannel进行数据发送和接收时,通常需要结合ByteBuffer类来完成数据的读取和写入。

  1. Pipe.SinkChannel和Pipe.SourceChannel:用于在同一进程内进行线程之间的通信,可以通过Pipe.SinkChannel向管道中写入数据,然后通过Pipe.SourceChannel从管道中读取数据。 Pipe是Java NIO中用于在两个线程之间进行通信的管道,其中包含了SinkChannel和SourceChannel两个通道。下面是Pipe.SinkChannel和Pipe.SourceChannel常用的方法:

Pipe.SinkChannel常用方法:

  1. write(ByteBuffer src):将指定的字节缓冲区中的数据写入到通道中。
  2. close():关闭通道。
  3. isOpen():判断通道是否处于打开状态。
  4. configureBlocking(boolean block):设置通道的阻塞模式。如果block为true,表示通道为阻塞模式,否则为非阻塞模式。
  5. validOps():返回此通道支持的操作集合。

Pipe.SourceChannel常用方法:

  1. read(ByteBuffer dst):从通道中读取数据,并将数据存储到指定的字节缓冲区中。
  2. close():关闭通道。
  3. isOpen():判断通道是否处于打开状态。
  4. configureBlocking(boolean block):设置通道的阻塞模式。如果block为true,表示通道为阻塞模式,否则为非阻塞模式。
  5. validOps():返回此通道支持的操作集合。

需要注意的是,Pipe是一个单向的通道,通过Pipe.SinkChannel向Pipe.SourceChannel传输数据。在使用Pipe进行通信时,一般会创建一个Pipe实例,并通过sink()source()方法获取对应的SinkChannel和SourceChannel对象,然后在不同的线程中使用这两个通道进行数据的读写操作。

Channel实现类 示例代码

这些Channel实现类都是抽象类,具体的实例化需要通过工厂方法来创建。在使用Channel进行数据读写时,需要结合Buffer类来完成数据的读写操作。 下面是一些Java示例代码,展示了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel、Pipe.SinkChannel和Pipe.SourceChannel的基本用法:

  1. FileChannel 示例代码:

java

代码解读

复制代码

import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class FileChannelExample {
    public static void main(String[] args) throws Exception {
        RandomAccessFile file = new RandomAccessFile("file.txt", "rw");
        FileChannel channel = file.getChannel();

        String data = "Hello, World!";
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put(data.getBytes());
        buffer.flip();

        channel.write(buffer);

        channel.close();
        file.close();
    }
}
  1. SocketChannel 示例代码:

java

代码解读

复制代码

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class SocketChannelExample {
    public static void main(String[] args) throws Exception {
        SocketChannel channel = SocketChannel.open();
        channel.connect(new InetSocketAddress("localhost", 8080));

        String data = "Hello, Server!";
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put(data.getBytes());
        buffer.flip();

        channel.write(buffer);

        buffer.clear();
        channel.read(buffer);
        buffer.flip();

        String response = new String(buffer.array(), 0, buffer.limit());
        System.out.println("Server response: " + response);

        channel.close();
    }
}
  1. ServerSocketChannel 示例代码:

java

代码解读

复制代码

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelExample {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.socket().bind(new InetSocketAddress(8080));

        SocketChannel channel = serverChannel.accept();

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        channel.read(buffer);
        buffer.flip();

        String request = new String(buffer.array(), 0, buffer.limit());
        System.out.println("Received request: " + request);

        String response = "Hello, Client!";
        buffer.clear();
        buffer.put(response.getBytes());
        buffer.flip();

        channel.write(buffer);

        channel.close();
        serverChannel.close();
    }
}
  1. DatagramChannel 示例代码:

java

代码解读

复制代码

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;

public class DatagramChannelExample {
    public static void main(String[] args) throws Exception {
        DatagramChannel channel = DatagramChannel.open();
        channel.bind(new InetSocketAddress(8080));

        ByteBuffer buffer = ByteBuffer.allocate(1024);
        channel.receive(buffer);
        buffer.flip();

        String request = new String(buffer.array(), 0, buffer.limit());
        System.out.println("Received request: " + request);

        String response = "Hello, Client!";
        buffer.clear();
        buffer.put(response.getBytes());
        buffer.flip();

        channel.send(buffer, new InetSocketAddress("localhost", 8888));

        channel.close();
    }
}
  1. Pipe.SinkChannel 和 Pipe.SourceChannel 示例代码:

java

代码解读

复制代码

import java.nio.ByteBuffer;
import java.nio.channels.Pipe;

public class PipeChannelExample {
    public static void main(String[] args) throws Exception {
        Pipe pipe = Pipe.open();
        Pipe.SinkChannel sinkChannel = pipe.sink();
        Pipe.SourceChannel sourceChannel = pipe.source();

        String data = "Hello, Pipe!";
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        buffer.put(data.getBytes());
        buffer.flip();

        sinkChannel.write(buffer);

        buffer.clear();
        sourceChannel.read(buffer);
        buffer.flip();

        String response = new String(buffer.array(), 0, buffer.limit());
        System.out.println("Received response: " + response);

        sinkChannel.close();
        sourceChannel.close();
    }
}

这些示例代码展示了不同类型的通道的基本用法,可以根据需要进行修改和扩展。请注意,这些示例仅用于演示目的,实际使用时需要进行适当的错误处理和资源释放。


转载来源:https://juejin.cn/post/7294130755840393279

相关文章
|
1月前
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
112 10
|
1月前
|
监控 Java API
如何使用Java语言快速开发一套智慧工地系统
使用Java开发智慧工地系统,采用Spring Cloud微服务架构和前后端分离设计,结合MySQL、MongoDB数据库及RESTful API,集成人脸识别、视频监控、设备与环境监测等功能模块,运用Spark/Flink处理大数据,ECharts/AntV G2实现数据可视化,确保系统安全与性能,采用敏捷开发模式,提供详尽文档与用户培训,支持云部署与容器化管理,快速构建高效、灵活的智慧工地解决方案。
|
20天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
38 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
7天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
55 13
|
6天前
|
存储 监控 Java
Java的NIO体系
通过本文的介绍,希望您能够深入理解Java NIO体系的核心组件、工作原理及其在高性能应用中的实际应用,并能够在实际开发中灵活运用这些知识,构建高效的Java应用程序。
24 5
|
12天前
|
算法 Java API
如何使用Java开发获得淘宝商品描述API接口?
本文详细介绍如何使用Java开发调用淘宝商品描述API接口,涵盖从注册淘宝开放平台账号、阅读平台规则、创建应用并申请接口权限,到安装开发工具、配置开发环境、获取访问令牌,以及具体的Java代码实现和注意事项。通过遵循这些步骤,开发者可以高效地获取商品详情、描述及图片等信息,为项目和业务增添价值。
46 10
|
6天前
|
前端开发 Java 测试技术
java日常开发中如何写出优雅的好维护的代码
代码可读性太差,实际是给团队后续开发中埋坑,优化在平时,没有那个团队会说我专门给你一个月来优化之前的代码,所以在日常开发中就要多注意可读性问题,不要写出几天之后自己都看不懂的代码。
42 2
|
15天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
开发框架 Java 关系型数据库
Java哪个框架适合开发API接口?
在快速发展的软件开发领域,API接口连接了不同的系统和服务。Java作为成熟的编程语言,其生态系统中出现了许多API开发框架。Magic-API因其独特优势和强大功能,成为Java开发者优选的API开发框架。本文将从核心优势、实际应用价值及未来展望等方面,深入探讨Magic-API为何值得选择。
42 2
|
1月前
|
监控 前端开发 Java
【技术开发】接口管理平台要用什么技术栈?推荐:Java+Vue3+Docker+MySQL
该文档介绍了基于Java后端和Vue3前端构建的管理系统的技术栈及功能模块,涵盖管理后台的访问、登录、首页概览、API接口管理、接口权限设置、接口监控、计费管理、账号管理、应用管理、数据库配置、站点配置及管理员个人设置等内容,并提供了访问地址及操作指南。
下一篇
DataWorks