# Java 通道教程 – NIO 2.0

> 原文: [https://howtodoinjava.com/java7/nio/java-nio-2-0-channels/](https://howtodoinjava.com/java7/nio/java-nio-2-0-channels/)

通道是继[**缓冲区**](//howtodoinjava.com/java-7/nio/java-nio-2-0-working-with-buffers/ "Java NIO 2.0 : Working With Buffers")之后的`java.nio`的第二项重大创新,我们在我之前的教程中已详细了解到。 通道提供与 I/O 服务的直接连接。 **通道是一种在字节缓冲区和通道另一端的实体(通常是文件或套接字)之间有效传输数据的介质。** 通常,通道与操作系统文件描述符具有一对一的关系。 通道类提供了维持平台独立性所需的抽象,但仍可以对现代操作系统的本机 I/O 能力进行建模。 通道是网关,通过它可以以最小的开销访问操作系统的本机 I/O 服务,而缓冲区是通道用来发送和接收数据的内部端点。

## NIO 通道基础

在层次结构的顶部,有[`Channel`](https://docs.oracle.com/javase/7/docs/api/java/nio/channels/Channel.html "Channel")接口,如下所示:

```java

package java.nio.channels;

public interface Channel

{

public boolean isOpen();

public void close() throws IOException;

}

```

由于依赖底层平台的各种因素,`Channel`实现在操作系统之间存在根本性的差异,因此通道 API(或接口)仅描述了可以完成的工作。 **`Channel`实现通常使用本机代码执行实际工作。 通过这种方式,通道接口使您能够以受控且可移植的方式访问低级 I/O 服务。**

从顶级`Channel`接口可以看到,所有通道只有两个共同的操作:检查通道是否打开(`isOpen()`)和关闭打开的通道(`close()`)。

## 打开通道

众所周知,I/O 分为两大类:**文件 I/O 和流 I/O** 。 因此,通道有两种类型也就不足为奇了:文件和套接字。 `FileChannel`类和`SocketChannel`类用于处理这两个类别。

仅可以通过在打开的`RandomAccessFile`,`FileInputStream`或`FileOutputStream`对象上调用`getChannel()`方法来获得`FileChannel`对象。 您不能直接创建`FileChannel`对象。

```java

RandomAccessFile raf = new RandomAccessFile ("somefile", "r");

FileChannel fc = raf.getChannel();

```

与`FileChannel`相反,套接字通道具有工厂方法来直接创建新的套接字通道。 例如

```java

//How to open SocketChannel

SocketChannel sc = SocketChannel.open();

sc.connect(new InetSocketAddress("somehost", someport));

//How to open ServerSocketChannel

ServerSocketChannel ssc = ServerSocketChannel.open();

ssc.socket().bind (new InetSocketAddress (somelocalport));

//How to open DatagramChannel

DatagramChannel dc = DatagramChannel.open();

```

上面的方法返回一个相应的套接字通道对象。 它们不是`RandomAccessFile.getChannel()`的新通道的来源。 如果已经存在,则它们返回与套接字关联的通道。 他们从不创造新的渠道。

## 使用通道

正如我们已经学习到缓冲区的教程一样,该教程介绍了通道与`ByteBuffer`对象之间的数据传输。 大多数读/写操作由从下面的接口实现的方法执行。

```java

public interface ReadableByteChannel extends Channel

{

public int read (ByteBuffer dst) throws IOException;

}

public interface WritableByteChannel extends Channel

{

public int write (ByteBuffer src) throws IOException;

}

public interface ByteChannel extends ReadableByteChannel, WritableByteChannel

{

}

```

**通道可以是单向或双向**。 给定的通道类可能实现`ReadableByteChannel`,它定义了`read()`方法。 另一个可能会实现`WritableByteChannel`以提供`write()`。 实现这些接口中的一个或另一个的类是单向的:它只能在一个方向上传输数据。 如果一个类实现两个接口(或扩展两个接口的`ByteChannel`),则它是双向的,可以双向传输数据。

如果您查看通道类,则会发现每个文件和套接字通道都实现了这三个接口。 就类定义而言,这意味着所有文件和套接字通道对象都是双向的。 对于套接字来说,这不是问题,因为它们始终是双向的,但是对于文件来说,这是一个问题。 从`FileInputStream`对象的`getChannel()`方法获得的`FileChannel`对象是只读的,但是在接口声明方面是双向的,因为 **`FileChannel`实现了`ByteChannel`** 。 在这样的通道上调用`write()`会抛出未选中的`NonWritableChannelException`,因为`FileInputStream`总是打开具有只读权限的文件。 因此,请记住,当通道连接到特定的 I/O 服务时,通道实例的特性将受到与其连接的服务的特性的限制。 连接到只读文件的`Channel`实例无法写入,即使该`Channel`实例所属的类可能具有`write()`方法。 程序员要知道如何打开通道,而不要尝试执行底层 I/O 服务不允许的操作。

```java

FileInputStream input = new FileInputStream ("readOnlyFile.txt");

FileChannel channel = input.getChannel();

// This will compile but will throw an IOException

// because the underlying file is read-only

channel.write (buffer);

```

`ByteChannel`的`read()`和`write()`方法将`ByteBuffer`对象作为参数。 每个都返回传输的字节数,该字节数可以小于缓冲区中的字节数,甚至为零。 缓冲区的位置将增加相同的量。 如果执行了部分传输,则可以将缓冲区重新提交给通道以继续传输数据,并从该处停止传输。 重复直到缓冲区的`hasRemaining()`方法返回`false`。

在下面的示例中,我们将数据从一个通道复制到另一个通道(*或从一个文件复制到另一个文件*):

```java

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.nio.ByteBuffer;

import java.nio.channels.ReadableByteChannel;

import java.nio.channels.WritableByteChannel;

public class ChannelCopyExample

{

public static void main(String args[]) throws IOException

{

FileInputStream input = new FileInputStream ("testIn.txt");

ReadableByteChannel source = input.getChannel();

FileOutputStream output = new FileOutputStream ("testOut.txt");

WritableByteChannel dest = output.getChannel();

copyData(source, dest);

source.close();

dest.close();

}

private static void copyData(ReadableByteChannel src, WritableByteChannel dest) throws IOException

{

ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);

while (src.read(buffer) != -1)

{

// Prepare the buffer to be drained

buffer.flip();

// Make sure that the buffer was fully drained

while (buffer.hasRemaining())

{

dest.write(buffer);

}

// Make the buffer empty, ready for filling

buffer.clear();

}

}

}

```

**通道可以在阻塞或非阻塞模式下运行。** 处于非阻塞模式的通道永远不会使调用线程进入睡眠状态。 所请求的操作要么立即完成,要么返回结果表明未完成任何操作。 只能将面向流的通道(例如套接字和管道)置于非阻塞模式。

## 关闭通道

要关闭通道,请使用其`close()`方法。 与缓冲区不同,**通道在关闭**后不能重新使用。 开放通道表示与特定 I/O 服务的特定连接,并封装了该连接的状态。 关闭通道后,该连接将丢失,并且该通道不再连接任何东西。

**在通道上多次调用`close()`是没有害处的。 随后在关闭通道上对`close()`的调用无济于事,并立即返回。**

可以想到,套接字通道可能需要大量时间才能关闭,具体取决于系统的网络实现。 某些网络协议栈可能会在输出耗尽时阻止关闭。

通道的打开状态可以使用`isOpen()`方法进行测试。 如果返回`true`,则可以使用该通道。 如果为`false`,则该通道已关闭,无法再使用。 尝试读取,写入或执行任何其他需要通道处于打开状态的操作将导致`ClosedChannelException`。

**祝您学习愉快!**

java 套接字关联的通道_Java 通道教程 – NIO 2.0相关推荐

  1. java套接字通信_JAVA套接字实现简易的双人通信系统

    JAVA套接字实现简易的双人通信系统 JAVA套接字资料 socket是基于应用服务与TCP/IP通信之间的一个抽象,他将TCP/IP协议里面复杂的通信逻辑进行分装,对用户来说,只要通过一组简单的AP ...

  2. java套接字编程_Java套接字编程:教程

    java套接字编程 本教程是Java套接字编程的简介,从一个简单的客户机-服务器示例开始,该示例演示了Java I / O的基本功能. 将向您介绍原始的java.io软件包和NIO,即Java 1.4 ...

  3. C语言socket bind()函数(为socket套接字关联了一个相应的地址与端口号)

    #include <sys/socket.h>int bind(int socket, const struct sockaddr *address, socklen_t address_ ...

  4. java套接字客户端_使用Java从客户端套接字读取数据(Read data from a client socket in Java)...

    使用Java从客户端套接字读取数据(Read data from a client socket in Java) 我编写了从客户端套接字发送/接收数据的代码. 发送数据步骤已成功完成,但是当我想从套 ...

  5. Java套接字程序_java – 通过Web套接字进行应用程序到应用程序的通信

    我通过Web套接字(没有浏览器工作)获得应用程序到应用程序的通信有些麻烦.由于这似乎不是最常用的网络套接字应用程序,我想知道是否有人有这方面的经验. 为什么我要使用网络套接字? 由于防火墙问题,我需要 ...

  6. Java 套接字(Socket)

    网络应用模式主要有: 主机/终端模式:集中计算,集中管理: 客户机/服务器(Client/Server,简称C/S)模式:分布计算,分布管理: 浏览器/服务器模式:利用Internet跨平台. www ...

  7. Java 套接字Socket

    套接字 一.概述 本质上是一套基于网络传输数据的流 实际上是一套用于网络通信的API IP地址 IPv4是指由4组数组成的IP地址 , 每组数的范围在0~255 .一共有2的32次方个地址(43亿多) ...

  8. Java套接字Socket编程--TCP参数

    在Java的Socket中,主要包含了以下可设置的TCP参数. 属性 说明 默认值 SO_TIMEOUT 对ServerSocket来说表示等待连接的最长空等待时间; 对Socket来说表示读数据最长 ...

  9. java 套接字 访问tcp_Java 网络编程(五) 使用TCP/IP的套接字(Socket)进行通信

    套接字Socket的引入 为了能够方便地开发网络应用软件,由美国伯克利大学在Unix上推出了一种应用程序访问通信协议的操作系统用调用socket(套接字). socket的出现,使程序员可以很方便地访 ...

最新文章

  1. LabVIEW图像增强算法(基础篇—5)
  2. “AI理论之父应该是哥德尔”,LSTM之父再抛惊人观点,网友:他有点走火入魔...
  3. Kerberos 原理简述
  4. java中执行js代码
  5. C# 获取文件大小,创建时间,文件信息,FileInfo类的属性表
  6. 【Leetcode | 1】93. 复原IP地址
  7. 解说redis中如何实现高可用
  8. [MicroPython]stm32f407控制DS18B20检测温度
  9. php更多式样,php_1
  10. docker公共存储库_Docker Hub镜像公共仓库使用
  11. python最适合做什么-学习Python适合就业哪些岗位?老男孩Python学习
  12. Hyperledger Fabric教程(9)-- peer命令-通道channel
  13. matlab矩阵论文,回归函数论文,关于基于Matlab矩阵运算的多元回归函数编程相关参考文献资料-免费论文范文...
  14. 讨厌的任意门事件,删了会出系统提示:安装prosheild.msi问题,不要乱删!
  15. C11 多线程初学1
  16. 第十七届全国大学生智能汽车竞赛全国总决赛参赛队伍奖项公告
  17. Ubuntu笔记本使用peek 来录制 gif 动画
  18. Adobe Dreamweaver的使用教程
  19. 生成Xcode中各个尺寸的Mac App Icon
  20. 移动端手机 摇一摇加声音

热门文章

  1. Mapping Persistence Classes 笔记2---ValueType的形式和映射
  2. python基础之常用模块
  3. 再谈Spring Boot中的乱码和编码问题
  4. 用Eclipse的snippets功能实现代码重用
  5. HashMap vs. TreeMap vs. Hashtable vs. LinkedHashMap
  6. 电路实验1-电容充放电
  7. extjs关于jsonreader
  8. C# 2进制、8进制、10进制、16进制...各种进制间的轻松转换
  9. ADO.NET 2.0中的SqlCommand.ExecutePageReader
  10. DllMain中不当操作导致死锁问题的分析--加载卸载DLL与DllMain死锁的关系