JAVA NIO技术(下)

其余功能介绍


看完以上陈述,详细大家对NIO有了一定的了解,下面主要通过几个案例,来说明NIO的其余功能,下面代码量偏多,功能性讲述偏少。


Scatter/Gatter


分散(scatter)从Channel中读取是指在读操作时将读取的数据写入多个buffer中。因此,Channel将从Channel中读取的数据“分散(scatter)”到多个Buffer中。


聚集(gather)写入Channel是指在写操作时将多个buffer的数据写入同一个Channel,因此,Channel 将多个Buffer中的数据“聚集(gather)”后发送到Channel。


scatter / gather经常用于需要将传输的数据分开处理的场合,例如传输一个由消息头和消息体组成的消息,你可能会将消息体和消息头分散到不同的buffer中,这样你可以方便的处理消息头和消息体。


案例:


import java.io.File;

import java.io.FileNotFoundException;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.OutputStream;

import java.nio.ByteBuffer;

import java.nio.channels.Channel;

import java.nio.channels.FileChannel;

 

public class ScattingAndGather

{

    public static void main(String args[]){

        gather();

    }

 

    public static void gather()

    {

        ByteBuffer header = ByteBuffer.allocate(10);

        ByteBuffer body = ByteBuffer.allocate(10);

 

        byte [] b1 = {'0', '1'};

        byte [] b2 = {'2', '3'};

        header.put(b1);

        body.put(b2);

 

        ByteBuffer [] buffs = {header, body};

 

        try

        {

            FileOutputStream os = new FileOutputStream("src/scattingAndGather.txt");

            FileChannel channel = os.getChannel();

            channel.write(buffs);

        }

        catch (IOException e)

        {

            e.printStackTrace();

        }

    }

}


transferFrom & transferTo


FileChannel的transferFrom()方法可以将数据从源通道传输到FileChannel中。


public static void method1(){

        RandomAccessFile fromFile = null;

        RandomAccessFile toFile = null;

        try

        {

            fromFile = new RandomAccessFile("src/fromFile.xml","rw");

            FileChannel fromChannel = fromFile.getChannel();

            toFile = new RandomAccessFile("src/toFile.txt","rw");

            FileChannel toChannel = toFile.getChannel();

 

            long position = 0;

            long count = fromChannel.size();

            System.out.println(count);

            toChannel.transferFrom(fromChannel, position, count);

 

        }

        catch (IOException e)

        {

            e.printStackTrace();

        }

        finally{

            try{

                if(fromFile != null){

                    fromFile.close();

                }

                if(toFile != null){

                    toFile.close();

                }

            }

            catch(IOException e){

                e.printStackTrace();

            }

        }

    }


方法的输入参数position表示从position处开始向目标文件写入数据,count表示最多传输的字节数。如果源通道的剩余空间小于 count 个字节,则所传输的字节数要小于请求的字节数。此外要注意,在SoketChannel的实现中,SocketChannel只会传输此刻准备好的数据(可能不足count字节)。因此,SocketChannel可能不会将请求的所有数据(count个字节)全部传输到FileChannel中。


transferTo()方法将数据从FileChannel传输到其他的channel中。


public static void method2()

   {

       RandomAccessFile fromFile = null;

       RandomAccessFile toFile = null;

       try

       {

           fromFile = new RandomAccessFile("src/fromFile.txt","rw");

           FileChannel fromChannel = fromFile.getChannel();

           toFile = new RandomAccessFile("src/toFile.txt","rw");

           FileChannel toChannel = toFile.getChannel();

 

           long position = 0;

           long count = fromChannel.size();

           System.out.println(count);

           fromChannel.transferTo(position, count,toChannel);

 

       }

       catch (IOException e)

       {

           e.printStackTrace();

       }

       finally{

           try{

               if(fromFile != null){

                   fromFile.close();

               }

               if(toFile != null){

                   toFile.close();

               }

           }

           catch(IOException e){

               e.printStackTrace();

           }

       }

   }


上面所说的关于SocketChannel的问题在transferTo()方法中同样存在。SocketChannel会一直传输数据直到目标buffer被填满。


Pipe


Java NIO 管道是2个线程之间的单向数据连接。Pipe有一个source通道和一个sink通道。数据会被写到sink通道,从source通道读取。


public static void method1(){

        Pipe pipe = null;

        ExecutorService exec = Executors.newFixedThreadPool(2);

        try{

            pipe = Pipe.open();

            final Pipe pipeTemp = pipe;

 

            exec.submit(new Callable<Object>(){

                @Override

                public Object call() throws Exception

                {

                    Pipe.SinkChannel sinkChannel = pipeTemp.sink();//向通道中写数据

                    while(true){

                        TimeUnit.SECONDS.sleep(1);

                        String newData = "Pipe Test At Time "+System.currentTimeMillis();

                        ByteBuffer buf = ByteBuffer.allocate(1024);

                        buf.clear();

                        buf.put(newData.getBytes());

                        buf.flip();

 

                        while(buf.hasRemaining()){

                            System.out.println(buf);

                            sinkChannel.write(buf);

                        }

                    }

                }

            });

 

            exec.submit(new Callable<Object>(){

                @Override

                public Object call() throws Exception

                {

                    Pipe.SourceChannel sourceChannel = pipeTemp.source();//向通道中读数据

                    while(true){

                        TimeUnit.SECONDS.sleep(1);

                        ByteBuffer buf = ByteBuffer.allocate(1024);

                        buf.clear();

                        int bytesRead = sourceChannel.read(buf);

                        System.out.println("bytesRead="+bytesRead);

                        while(bytesRead >0 ){

                            buf.flip();

                            byte b[] = new byte[bytesRead];

                            int i=0;

                            while(buf.hasRemaining()){

                                b[i]=buf.get();

                                System.out.printf("%X",b[i]);

                                i++;

                            }

                            String s = new String(b);

                            System.out.println("=================||"+s);

                            bytesRead = sourceChannel.read(buf);

                        }

                    }

                }

            });

        }catch(IOException e){

            e.printStackTrace();

        }finally{

            exec.shutdown();

        }

    }


DatagramChannel


Java NIO中的DatagramChannel是一个能收发UDP包的通道。因为UDP是无连接的网络协议,所以不能像其它通道那样读取和写入。它发送和接收的是数据包。


public static void  reveive(){

       DatagramChannel channel = null;

       try{

           channel = DatagramChannel.open();

           channel.socket().bind(new InetSocketAddress(8888));

           ByteBuffer buf = ByteBuffer.allocate(1024);

           buf.clear();

           channel.receive(buf);

 

           buf.flip();

           while(buf.hasRemaining()){

               System.out.print((char)buf.get());

           }

           System.out.println();

 

       }catch(IOException e){

           e.printStackTrace();

       }finally{

           try{

               if(channel!=null){

                   channel.close();

               }

           }catch(IOException e){

               e.printStackTrace();

           }

       }

   }

 

   public static void send(){

       DatagramChannel channel = null;

       try{

           channel = DatagramChannel.open();

           String info = "I'm the Sender!";

           ByteBuffer buf = ByteBuffer.allocate(1024);

           buf.clear();

           buf.put(info.getBytes());

           buf.flip();

 

           int bytesSent = channel.send(buf, new InetSocketAddress("10.10.195.115",8888));

           System.out.println(bytesSent);

       }catch(IOException e){

           e.printStackTrace();

       }finally{

           try{

               if(channel!=null){

                   channel.close();

               }

           }catch(IOException e){

               e.printStackTrace();

           }

       }

   }


可以通过阅读参考资料2和3了解更多的NIO细节知识,前人栽树后人乘凉,这里就不赘述啦。


参考资料


1. Java NIO

2. Java NIO 系列教程

3. Java NIO 详解

4. 《深入分析Java Web技术内幕》许令波 著

5. java大文件读写操作,java nio 之MappedByteBuffer,高效文件/内存映射

6. java nio 之MappedByteBuffer,高效文件/内存映射

你可能感兴趣的:(JAVA NIO技术(下))