Java NIO之Channel

Java NIO Channel详解 Channel通道在JAVA NIO中,基本上所有的IO都是从Channel开始的,读取操作即从Channel读到Buffer,写操作即从Buffer写入Channel。在网络IO方面,Channel的主要实现是DatagramChannel、SocketChannel和ServerSocketChannel, DatagramChannel 能通过UDP读写网络中的数据。 SocketChanne 阅读详情

Java NIO之Channel


介绍

定义

Channel(管道):A channel represents an open connection to an entity such as a hardware device, a file, a network socket, 
or a program component that is capable of performing one or more distinct I/O operations, for example reading or writing.

管道可以将其理解为一条连接,可以通过这条连接传输数据。

java nio数据传输介质是管道,就像java io中数据传输介质是流一样。不过io中的流是分方向的输入流和输出流,
但是nio的管道是双向的既可以输出数据也可以读取数据。当然管道都是基于Buffer对象读取和写入数据的。

java nio借助Channel和Selector实现单线程的多路复用IO.在聊天服务器中会使用到这种技术。

管道传输数据示意图

channel 管道传输数据示意图


Channel实现

Channel接口的实现有:
FileChannel(操作文件相关)
SocketChannel(TCP通信模型客户端Channel)
ServerSocketChannel(TCP通信服务器端Channel)
DatagramChannel(UDP数据报Channel)


备注:以下的学习时基于FileChannel来实现和学习的,其它几个Channel实现在网络高级编程中会使用到。

Channel接口

Channel接口就只定义了两个方法isOpen()和close()方法。

/**
 * 管道表示和磁盘、文件、网络套接字或程序组件的一条连接,它可以用来执行IO操作比如读取数据或写入数据。
 * 
 * A channel represents an open connection to an entity such as a hardware
 * device, a file, a network socket, or a program component that is capable of
 * performing one or more distinct I/O operations, for example reading or
 * writing.
 *
 * Channels are, in general, intended to be safe for multithreaded access
 * as described in the specifications of the interfaces and classes that extend
 * and implement this interface.
 */

public interface Channel extends Closeable {

    /**
     * Tells whether or not this channel is open.  </p>
     */
    public boolean isOpen();

    /**
     * Closes this channel.
     */
    public void close() throws IOException;

}

jdk nio隐藏细节太多了,如果真要看源码最好还是看openjdk的源码

FileChannel文件管道应用

FileChannel是一个抽象类,可以通过以下方法获得其实例对象

FileInputStream.getChannel()
FileOutputStream.getChannel()
RandomAccessFile.getChannel()

FileChannel核心方法

/**
 * A channel for reading, writing, mapping, and manipulating a file.
 */

public abstract class FileChannel
extends AbstractInterruptibleChannel
implements SeekableByteChannel, GatheringByteChannel, ScatteringByteChannel
{

    // -- Channel operations --

    /**
     * Reads a sequence of bytes from this channel into the given buffer.
     *
     * Bytes are read starting at this channel's current file position, and
     * then the file position is updated with the number of bytes actually
     * read.  Otherwise this method behaves exactly as specified in the 
     * ReadableByteChannel interface. 
     */
    public abstract int read(ByteBuffer dst) throws IOException;

    /**
     * Writes a sequence of bytes to this channel from the given buffer.
     *
     * Bytes are written starting at this channel's current file position
     * unless the channel is in append mode, in which case the position is
     * first advanced to the end of the file.  The file is grown, if necessary,
     * to accommodate the written bytes, and then the file position is updated
     * with the number of bytes actually written.  Otherwise this method
     * behaves exactly as specified by the  WritableByteChannel
     * interface. 
     */
    public abstract int write(ByteBuffer src) throws IOException;


    // -- Other operations --

    /**
     * Returns this channel's file position.
     */
    public abstract long position() throws IOException;

    /**
     * Sets this channel's file position.
     */
    public abstract FileChannel position(long newPosition) throws IOException;

    /**
     * Returns the current size of this channel's file.
     */
    public abstract long size() throws IOException;

    /**
     * Truncates this channel's file to the given size.
     *
     * If the given size is less than the file's current size then the file
     * is truncated, discarding any bytes beyond the new end of the file.  If
     * the given size is greater than or equal to the file's current size then
     * the file is not modified.  In either case, if this channel's file
     * position is greater than the given size then it is set to that size.
     * 
     */
    public abstract FileChannel truncate(long size) throws IOException;

    /**
     * Transfers bytes from this channel's file to the given writable byte
     * channel.
     */
    public abstract long transferTo(long position, long count,
                                    WritableByteChannel target)
        throws IOException;

    /**
     * Transfers bytes into this channel's file from the given readable byte
     * channel.
     */
    public abstract long transferFrom(ReadableByteChannel src,
                                      long position, long count)
        throws IOException;

    /**
     * Reads a sequence of bytes from this channel into the given buffer,
     * starting at the given file position.
     */
    public abstract int read(ByteBuffer dst, long position) throws IOException;

    /**
     * Writes a sequence of bytes to this channel from the given buffer,
     * starting at the given file position.
     */
    public abstract int write(ByteBuffer src, long position) throws IOException;


    // -- Memory-mapped buffers --

    /**
     * Maps a region of this channel's file directly into memory.
     * 具体参考源码
     */
    public abstract MappedByteBuffer map(MapMode mode,
                                         long position, long size)
        throws IOException;


    // -- Locks --

    /**
     * Acquires an exclusive lock on this channel's file.
     *
     * An invocation of this method of the form fc.lock() behaves
     * in exactly the same way as the invocation
     */
    public final FileLock lock() throws IOException {
        return lock(0L, Long.MAX_VALUE, false);
    }

    /**
     * Attempts to acquire an exclusive lock on this channel's file.
     *
     * An invocation of this method of the form fc.tryLock()
     * behaves in exactly the same way as the invocation
     */
    public final FileLock tryLock() throws IOException {
        return tryLock(0L, Long.MAX_VALUE, false);
    }

}


FileChannel的position和Buffer的position属性是不同的意思,FileChannel的position指的是文件指针位置,
Buffer的position指的是子节数组中下标位置。

FileChannel读写数据分析

ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put("hello".getBytes());

//从Buffer对象中读取数据时,要先调用flip方法
buffer.flip();
fileChannel.write(buffer);

备注:因为调用write(buffer)写入数据到管道中时,只能读取Buffer对象中position到limit之间的数据, 
如果不调用flip方法的话,读取到的Buffer数据可能就是错误的或0。


//向Buffer对象中写入数据时,要先调用clear()方法。
buffer.clear();
fileChannel.read(buffer);

备注:因为调用read(buffer)从管道中读取数据到管道时,如果不先调用clear方法, 
那么Buffer对象就不一定是从position为0开始写入数据了,就会导致写入数据到Buffer对象是错误的。


备注:重点还是在于Buffer对象的那几个变量值,即position、limit、capacity。最关键的是position和limit,因为容量初始化之后通常不会变的。

FileChannel的文件拷贝

FileChannel自带的拷贝方法

//nio中Channle 自带提供的拷贝方法
public void testCopyFile2() throws Exception {

    // 源文件
    FileInputStream inputStream = new FileInputStream(new File("e:/nio/test.jpg"));
    // 目标文件
    FileOutputStream outputStream = new FileOutputStream(new File("e:/nio/copy.jpg"));

    // 获得源文件的通道
    FileChannel inChannel = inputStream.getChannel();
    // 获得目标文件的通道
    FileChannel outChannel = outputStream.getChannel();

    // nio自带的考本文件方法
    //1、transferFrom(ReadableByteChannel src,long position, long count)
    outChannel.transferFrom(inChannel, 0, inChannel.size());
    //2、transferTo(long position, long count,WritableByteChannel target)
    inChannel.transferTo(0, inChannel.size(), outChannel);

    //备注这两个方法是等效的,只是要注意文件读写模式。

    //关闭资源 ...

}

基于FileChannel和ByteBuffer实现拷贝

//基于ByteBuffer和FileChannel的文件拷贝
public void testCopyFile() throws Exception {

    // 源文件
    FileInputStream inputStream = new FileInputStream(new File("e:/nio/2.jpg"));
    // 目标文件
    FileOutputStream outputStream = new FileOutputStream(new File("e:/nio/2copy.jpg"));

    // 获得源文件的通道
    FileChannel inChannel = inputStream.getChannel();
    // 获得目标文件的通道
    FileChannel outChannel = outputStream.getChannel();

    ByteBuffer buffer = ByteBuffer.allocate(10);

    boolean flag = true;
    while (flag) {
        buffer.clear();
        // 从管道(和源文件建立的管道)读取数据到buffer对象中
        int data = inChannel.read(buffer);
        buffer.flip();
        if (data == -1) {// 一直读写直到没有数据时退出循环
            flag = false;
        }
        // 从buffer对象中读取数据到管道(通过目标文件建立的管道)
        outChannel.write(buffer);

    }
    //关闭资源
}


我对ByteBuffer对象的理解,是根据结构化的的子节数组,对现实内存的抽象。

关于Buffer的flip()和clear()方法,我的理解是当从Buffer对象中读取数据时,那么要先调用flip()方法, 
当要向Buffer对象中写入数据时,要先调用clear()方法。

总结

总结其实学习nio最重要的不是学会它们如何操作,因为步骤性的技术通常是冗长难以记忆的,只要长时间不用就可能会生疏, 
但是原理性的东西是内容量比较少的,所以掌握其最核心原理很重要。

参考

1、http://www.ibm.com/developerworks/cn/education/java/j-nio/section5.html
2、http://ifeve.com/file-channel/
3、http://www.cnblogs.com/dolphin0520/p/3916526.html

西门子PLC实战:基于1200/1500的工业物联网MQTT通讯全解析 本文详细解析了如何在西门子S7-1200/1500系列PLC上实现工业物联网MQTT通讯。通过从硬件准备、网络配置到TIA Portal中MQTT_Client功能块的实战编程,手把手指导工程师打通车间数据桥梁,解决信息孤岛问题,实现PLC数据高效上云或设备间互联。 阅读详情

相关推荐

GD32F407工程模板搭建全记录:从零整理固件库、创建文件夹到编译通过

本文详细记录了GD32F407工程模板的搭建过程,从固件库整理、目录规划到Keil环境配置,帮助开发者快速搭建可维护的嵌入式工程结构。重点介绍了开发环境搭建、工程目录设计、Keil配置及常见编译问题解决方案,适合嵌入式开发者参考。

weixin_29164497的博客 92

嘿牛程序员__成都传智博客__文件的拷贝:单个文件的拷贝(下)

---------------------- android培训、java培训、期待与您交流! ---------------------- 本节继续研究单个文件的拷贝 前面我们主要采用了两种方法,一种是通过字节流,一种是被包装称字符流。那么我们是否可以选取一种整体移动的方法,于是我们就想到了通道。 下面我们主要通过通道FileChannel,以及方法getChannel()、transfe

休哥的博客_嘿牛程序员_成都传智博客 1810

电商用户行为数据集.rar

背景描述本数据集汇集了某个电商平台的用户基本信息、行为习惯和互动数据。它包括用户的年龄、性别、居住地区、收入水平等基本属性,以及他们的兴趣偏好、登录频率、购买行为和平台互动等动态指标。数据集关注的焦点在于电商领域,旨在通过用户行为的深入分析,揭示其偏好和需求。通过这些数据,商家能够更好地理解消费者,制定有效的市场策略,满足用户期望,推动业务发展。image.png数据说明字段说明User_ID每个用户的唯一标识符,便于追踪和分析。Age用户的年龄,提供对人口统计偏好的洞察。Gender用户的性别,使能性别特定的推荐和定位。Location用户所在地区:郊区、农村、城市,影响偏好和购物习惯。Income用户的收入水平,表明购买力和支付能力。Interests用户的兴趣,如运动、时尚、技术等,指导内容和产品推荐。Last_Login_Days_Ago用户上次登录以来的天数,反映参与频率。Purchase_Frequency用户进行购买的频率,表明购物习惯和忠诚度。Average_Order_Value用户下单的平均价值,对定价和促销策略至关重要。Total_Spending用户消费的总金额,表明终身价值和购买行为。Product_Category_Preference用户偏好的特定产品类别。Time_Spent_on_Site_Minutes用户在电子商务平台上花费的时间,表明参与程度。Pages_Viewed用户在访问期间浏览的页面数量,反映浏览活动和兴趣。Newsletter_Subscription用户是否订阅了营销活动通知。

FileChannel应用实例——拷贝文件transferFrom方法

package com.atguigu.nio; import java.io.FileInputStream; import java.io.FileOutputStream; import java.nio.channels.FileChannel; public class NIOFileChannel04 { public static void main(String[] args) throws Exception { //创建相关流 Fil...

qq_39368007的博客 2223

Channel(通道)之FileChannel

Channel(通道)之FileChannel类 FileChannel类的基本使用 获取FileChannel类的对象 java.nio.channels.FileChannel (抽象类):用于读、写文件的通道 FileChannel是抽象类,我们可以通过FileInputStream和FileOutputStreamgetChannel()方法方便的获取一个它的子类对象。 FileInputStream fi=new FileInputStream(new File(src));

weixin_53589418的博客 631

Java NIO系列教程(五) 通道之间的数据传输

Java NIO中,如果两个通道中有一个是FileChannel,那你可以直接将数据从一个channel(译者注:channel中文常译作通道)传输到另外一个channeltransferFrom() FileChanneltransferFrom()方法可以将数据从源通道传输到FileChannel中(译者注:这个方法在JDK文档中的解释为将字节从给定的可读取字节通道传输到此通道的文...

limeOracle的博客 246

简单的使用Java IO和NIO

 功能:将一个TXT文件保存到另一个文件; public static void main(String[] args) throws Exception { //得到一个文件的输入流 FileInputStream inputStream = new FileInputStream("C:\\Users\\jinzheyi\\Desktop\\some2.txt");...

Lujunwei0205的博客 234

Java NIO 总结: Channel 通道

Java NIO中,Channel是一个核心概念,它表示一个打开的连接,可以连接到I/O设备(如磁盘文件、Socket)或者一个支持I/O访问的应用程序。与传统的IO操作相比,NIO通过Channel和Buffer相结合,提高了IO性能和数据传输效率。ChannelJava NIO中的一个核心概念,它提供了一种高效、非阻塞的IO操作方式。通过Channel和Buffer的结合使用,提高了IO性能和数据传输效率。在实际应用中,可以根据需求选择不同的Channel实现来进行高效的IO操作。

码到三十五 2577

java NIO-Channel

1 概述 之前听朋友说,他们公司有一个业务场景对于IO的操作要求较高,项目组长让他用NIO来完成这个需求,他一听一脸茫然的问组长:啥是NIO啊?项目组长听后对他挥挥手说:“起开起开,我来”。朋友后来和我分享这个事情,对于都是菜鸡的我们来说,我也不知道啥叫NIO。于是虎年伊始,我决定来学学这个NIO。以免有一天我的项目组长对我说,你起开起开,我来。 Java NIOJava1.4之后引入的一个全新的API,它可以替代标准的IO操作,NIO既支持面向缓冲区的操作,同时也是基...

爪哇人的博客 958

总结了才知道,原来Java NIOchannel是这么用的!

Java NIOChannel类似流,是用于传输数据的数据流,但有不同: 既可从通道中读取数据,又可写数据到通道。但流的读写通常单向 通道可异步读写 通道中的数据总要先读到一个Buffer或从一个Buffer中写入 从Channel读数据到缓冲区,从缓冲区写数据到ChannelChannel的实现 Java NIO中最重要的Channel的实现: FileChannel 从文件中读写数据 DatagramChannel 通过UDP读写网络中的数据 SocketChannel 通过TCP读写网络

JavaEdge全是干货的技术号 2030

JavaNIOChannel通道

1.Channel 通道的简介javaNIO的通道类似流,但是又有一些不同: - 既可以从Channel中读数据也可以往Channel里面写数据;但是流的读写一般是单向的。 - Channel可以异步的读写; - Channel的读写是通过Buffer这个中介实现的。数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。如下图所示:引用一段关于描述Channel的文字:

惜暮 1416

四、JAVA NIO (Channel)

NIO 目录 文章目录四、JAVA NIO (Channel)1、Channel 概述2、Channel 实现3、FileChannel 介绍和示例4、FileChannel 操作详解4.1、打开 FileChannel4.2、从 FileChannel 读取数据4.3、向 FileChannel 写数据4.4、关闭 FileChannel4.5、FileChannel 的 position 方法4.6、FileChannel 的 size 方法4.7、FileChannel 的 truncate 方法4

wang_luwei的博客 1907

Java NIO - Buffer & Channel

Java NIO Java NIOjava non-blocking IO,从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,是同步非阻塞的 NIO三大核心部分: Channel(通道) Buffer(缓冲区) Selector(选择器) NIO是面向缓冲区,或者面向块编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络 Java NIO的非阻塞模式,使一个线程从某通过发送请求或者读取数据,但是它仅能

了凡 888

[八]JavaIO之FileInputStream 与 FileOutputStream

接下来介绍 FileInputStream 和 FileOutputStream 现在看名字应该可以看得出来: 他就是从一个文件中读取数据 或者将数据写入到一个文件中 FileInputStream 既然是从文件读取数据,那么自然要记录文件本身的信息 所以有文件描述符 fd以及 path路径名 显然,文件描述符是对文件最直接的描述 ...

noteless的博客 301

Java 入门指南:Java NIO —— Channel(通道)

通道(Channel)是 `NIO`(New Input/Output)模型中的一个重要概念。通道代表着与底层 I/O 设备(如文件、网络套接字等)之间的连接,用于将数据传输到缓冲区或从缓冲区传输数据。 Channel 不与数据打交道,它只负责运输数据 通道在 NIO 中起到了桥梁作用,负责将数据从缓冲区传输到通道或者从通道传输到缓冲区。它是一个双向的数据传输通道。

热带鱼的技术博客 2666

java niochannel和操作系统的关系

在操作系统中对IO设备的控制方式一共有四种,按时间线依次是轮询、中断、DMA、和通道方式 轮询就是进行IO时操作系统一直问控制器数据准备好了没有。 中断就是异步的方式进行了,CPU向设备控制器发送一条IO指令后接着返回继续做原来的工作,而当设备控制器从设备中取出数据放到控制器的寄存器中后便向CPU发送中断信号,CPU在检查完数据后便向控制器发送取走数据的信号,将数据写入内存,但仍是以字节为单位的。...

Talk is cheap,show me the code 1155

java导出文件有返回值,Java FileOutputStream getChannel()方法与示例

FileOutputStreamgetChannel()方法getChannel()方法在java.io包中可用。getChannel()方法用于返回与此FileOutputStream链接的独特FileChannelgetChannel()方法是一个非静态方法,只能通过类对象访问,如果尝试使用类名称访问该方法,则会收到错误消息。getChannel()方法在返回通道时不会引发异常。语法:pu...

weixin_28937075的博客 1165

JavaNIO】通道Channel

JavaNIO三大件之一的Channel

Wligt的博客 266
上一篇: Python 14:Python网络请求模块
下一篇: Java NIO之Charset类字符编码对象
nicewuranran
博客等级 码龄14年 47粉丝 170原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值