JAVA NIO学习笔记之Channel(基础篇)

这次讲的是JAVA NIO中的大boss:Channel。同样,我只挑重要的类和方法来讲。

Channel 用于在字节缓冲区和位于通道另一侧的实体(通常是一个文件或套接字)之间有效地传输数据,它能大大提高读写效率,是NIO中的重大突破。也是广大java开发者必须要掌握的

I/O 可以分为广义的两大类别:File I/O 和 Stream I/O。那么相应地有两种类型的通道也就不足为怪了,它们是文件( file)通道和套接字( socket)通道。

有一个 FileChannel 类和三个 socket 通道类: SocketChannelServerSocketChannel DatagramChannel。这篇博文只要讲一些基础,而关于两种通道类的具体实现我们将放在进阶篇中做详细讲解

接下来我们直接上代码,根据代码进行讲解。

获取通道类

SocketChannel sc = SocketChannel.open( );
sc.connect (new InetSocketAddress ("somehost", someport));
ServerSocketChannel ssc = ServerSocketChannel.open( );
ssc.socket( ).bind (new InetSocketAddress (somelocalport));
DatagramChannel dc = DatagramChannel.open( );
RandomAccessFile raf = new RandomAccessFile ("somefile", "r");
FileChannel fc = raf.getChannel( );

以上代码是刚刚提到的四种通道类的创建方式,需要注意的是创建socket通道时,socket类同样有一个getChannel方法来返回SocketChannel,但是该方法的作用是在已经存在SocketChannel时返回该SocketChannel,而不能新建一个SocketChannel。要想新建一个SocketChannel,你只能通过上述的SocketChannel的open方法。而FileChannel 则不同,它可以通过file的getChannel方法新建。

另外,如果想通过I/O流去获取通道,则用Channels的静态方法newChannel即可

操作通道类

操作通道类的方法主要是write和read,针对不同通道类读写缓冲区。这里要注意的是区分你要操作的通道类的类型是只读还是读写,举个例子你如果通过FileInputStream获取了一个FileChannel,那么这个FileChannel就是只读的,这时候你如果执行write方法是会报错的。

上代码:

package com.java.cheney.nio;

import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.channels.Channels;
import java.io.IOException;

/**
 * 
 * Project: javaDemo
 * Class: ChannelCopy
 * Description:通过通道进行复制
 * 
 * @author : Cheney
 * @Date 2016年5月22日 上午10:32:02
 * @version 1.0
 * 
 */
public class ChannelCopy {
    
    public static void main(String[] argv) throws IOException {
        ReadableByteChannel source = Channels.newChannel(System.in);
        WritableByteChannel dest = Channels.newChannel(System.out);
        channelCopy1(source, dest);
        //或者替换成channelCopy2(source, dest);
        source.close();
        dest.close();
    }

    private static void channelCopy1(ReadableByteChannel src,
            WritableByteChannel dest) throws IOException {
        //为缓冲区分配大小
        ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
        //读取缓冲区直到结束
        while (src.read(buffer) != -1) {
            buffer.flip();
            // 通过通道将dest中的内容写入缓冲区
            dest.write(buffer);
            //压缩缓冲区,进行下一次循环
            buffer.compact();
        }
        
        buffer.flip();
        //检测缓冲区是否清空
        while (buffer.hasRemaining()) {
            dest.write(buffer);
        }
    }

    private static void channelCopy2(ReadableByteChannel src,
            WritableByteChannel dest) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024);
        //读取缓冲区直到结束
        while (src.read(buffer) != -1) {
            buffer.flip();
            while (buffer.hasRemaining()) {
                dest.write(buffer);
            }
            //清空缓冲区
            buffer.clear();
        }
    }
}

这个程序的功能是你可以通过控制台输入数据到ReadableByteChannel后又被复制到WritableByteChannel后输出,基本的读写操作都在上面包含了~

Scatter/Gather

它是指在多个缓冲区上实现一个简单的 I/O 操作。对于一个 write 操作而言,数据是从几个缓冲区按顺序抽取(称为 gather)并沿着通道发送的。对于 read 操作而言,从通道读取的数据会按顺序被散布(称为 scatter)到多个缓冲区。这一重大的突破目的在于提升读写的性能

上代码:

package com.java.cheney.nio;

import java.nio.ByteBuffer;
import java.nio.channels.GatheringByteChannel;
import java.io.FileOutputStream;
import java.util.Random;
import java.util.List;
import java.util.LinkedList;

/**
 * 
 * Project: javaDemo Class: Marketing Description:
 * 
 * @author : Cheney
 * @Date 2016年5月22日 上午11:02:05
 * @version 1.0
 * 
 */
public class Marketing {
    private static final String outputFile = "blahblah.txt";

    // "Leverage frictionless methodologies"
    public static void main(String[] argv) throws Exception {
        int reps = 10;
        if (argv.length > 0) {
            //输入的数据代表输出文件的行数,缺省值为10
            reps = Integer.parseInt(argv[0]);
        }
        FileOutputStream fos = new FileOutputStream(outputFile);
        //获取GatheringByteChannel
        GatheringByteChannel gatherChannel = fos.getChannel();
        // utterBS方法的作用是返回将要写在文件中的内容的字节缓冲数组
        ByteBuffer[] bs = utterBS(reps);
        // 此循环的作用是将所有在通道里的内容输出
        while (gatherChannel.write(bs) > 0) {
        }
        System.out.println("Mindshare paradigms synergized to " + outputFile);
        fos.close();
    }

    private static String[] col1 = { "Aggregate", "Enable", "Leverage",
            "Facilitate", "Synergize", "Repurpose", "Strategize", "Reinvent",
            "Harness" };
    private static String[] col2 = { "cross-platform", "best-of-breed",
            "frictionless", "ubiquitous", "extensible", "compelling",
            "mission-critical", "collaborative", "integrated" };
    private static String[] col3 = { "methodologies", "infomediaries",
            "platforms", "schemas", "mindshare", "paradigms",
            "functionalities", "web services", "infrastructures" };
    private static String newline = System.getProperty("line.separator");

    private static ByteBuffer[] utterBS(int howMany) throws Exception {
        List list = new LinkedList();
        for (int i = 0; i < howMany; i++) {
            //pickRandom为获取随机数的操作
            list.add(pickRandom(col1, " "));
            list.add(pickRandom(col2, " "));
            list.add(pickRandom(col3, newline));
        }
        ByteBuffer[] bufs = new ByteBuffer[list.size()];
        //将list转换成数组存入bufs
        list.toArray (bufs);
        return (bufs);
    }

    private static Random rand = new Random();

    private static ByteBuffer pickRandom(String[] strings, String suffix)
            throws Exception {
        //获取随机字符串
        String string = strings[rand.nextInt(strings.length)];
        int total = string.length() + suffix.length();
        ByteBuffer buf = ByteBuffer.allocate(total);
        buf.put(string.getBytes("US-ASCII"));
        buf.put(suffix.getBytes("US-ASCII"));
        buf.flip();
        return (buf);
    }
}
这段程序可以大概描述出scatter/gather的大致思想,即同时读取多个缓冲区和同时写入多个缓冲区

 

以上是channel的基础部分,之后我们将进一步研究以后会广泛应用的file通道和socket通道

转载于:https://my.oschina.net/CheneyLee/blog/685876

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值