JAVA NI/O学习-Channel

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Channel类似于传统的流对象,但与传统的流不同的是,Channel有两个主要的区别
(1)Channel可以直接将指定的文件的部分或全部直接映射成Buffer
(2)程序不能直接访问Channel中的数据,包括读、写都不行,Channel只能与Buffer进行交互。也就是说,如果要从Channel中取得数据,必须先用BufferChannel中取出一些数据,然后让程序从Buffer中取出这些数据。如果要将程序中的数据写入Channel,一样先让程序将数据放入Buffer中,程序再将Buffer里的输入写入Channel.

  Channel是一个接口,位于java.nio.channels,系统为该接口提供了DatagramChannel,FileChannel,Pipe.SinkChannel,Pipe.SourceChannel,SelectableChannel,ServerSocketChannel,SocketChannel等实现类.。例如.Pipe.SinkChannel,Pipe.SourceChanel用于支持线程之间通信的管道Channel,ServerSocketChannel,SocketChannel则是用于支持TCP网络通信的Channel
  所有的Channel都不应该通过构造器来直接创建,而是通过传统的节点InputStream,OutputStreamgetChannel方法来返回对应的Channel,不同的节点流获得的Channel不一样,例如FileInputStream,FileOutputStreamgetChannel返回的是FileChannel,PipedInputStreamPipedOutputStreamgetChannel返回的是Pipe.SinkChannel,Pipe.SourceChannel
  Channel中最常用的三类方法是map,read, write,其中map方法用于将Channel对应的部分或全部数据映射成ByteBuffer,readwrite方法都有一系列重载形式,这些方法用于从Buffer中读取数据或向Buffer里写入数据.
  其中map方法的方法签名为 MappedByteBuffer map(FileChannel.MapMode mode,long position,long size):第一个参数执行映射时的模式,分别有只读,读写模式,而第二个,第三个参数用于控制将Channel的哪些数据映射成ByteBuffer

 

示例一
 直接将FileChannel的全部数据映射成ByteBuffer的效果

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;
public class FileChannelTest
{
 public static void main(String[] args)
 {
  FileChannel inChannel = null;
  FileChannel outChannel = null;
  try
  {
   File f = new File("FileChannelTest.java");
   //创建FileInputStream,以该文件输入流创建FileChannel
   inChannel = new FileInputStream(f).getChannel();
   //将FileChannel里的全部数据映射成ByteBuffer
   MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,
    0 , f.length());
   //使用GBK的字符集来创建需要编码器
   Charset charset = Charset.forName("GBK");
   //以文件输出流创建FileBuffer,用以控制输出
   outChannel = new FileOutputStream("a.txt").getChannel();
   //直接将buffer里的数据全部输出
   outChannel.write(buffer);
   //再次调用buffer的clear()方法,复原limit、position的位置
   buffer.clear();
   //创建解码器(CharsetDecoder)对象
   CharsetDecoder decoder = charset.newDecoder();
   //使用解码器将ByteBuffer转换成CharBuffer
   CharBuffer charBuffer =  decoder.decode(buffer);
   //CharBuffer的toString方法可以获取对应的字符串
   System.out.println(charBuffer);
  }
  catch (IOException ex)
  {
   ex.printStackTrace();
  }
  finally
  {
   try
   {
    if (inChannel != null)
     inChannel.close();
    if (outChannel != null)
     outChannel.close(); 
   }
   catch (IOException ex)
   {
    ex.printStackTrace();
   }
  }
 }
}



 


 示例二
 不仅InputStream,OutputStream包含了getChannel方法,在RandomAccessFile中也包含了一个getChannel方法,由RandomAccessFile返回的FileChannel是只读的,还是读写的Channel则取决于RandomAccessFile打开文件的模式。
 如下例子,会把a.txt文件复制出来,追加到该文件后面
  

import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.nio.charset.*;

public class RandomFileChannelTest
{
 public static void main(String[] args)
 {
  FileChannel randomChannel = null;
  try
  {
   File f = new File("a.txt");
   //创建一个RandomAccessFile对象
   RandomAccessFile raf = new RandomAccessFile(f, "rw");
   //获取RandomAccessFile对应的Channel
   randomChannel = raf.getChannel();
   //将Channel中所有数据映射成ByteBuffer
   ByteBuffer buffer = randomChannel.map(FileChannel.MapMode.READ_ONLY,
    0 , f.length());
   //把Channel的记录指针移动到最后
   randomChannel.position(f.length());
   //将buffer中所有数据输出
   randomChannel.write(buffer);
  }
  catch (IOException ex)
  {
   ex.printStackTrace();
  }
  finally
  {
   try
   {
    if (randomChannel != null)
     randomChannel.close();
   }
   catch (IOException ex)
   {
    ex.printStackTrace();
   }
  }
 }
}

示例三
如果我们习惯了传统IOBuffer来多次重次取数据的过程,或者担心Channel对应的文件过大,使用Map方法一次将所有的文件映射到内存中引起性能下降,也可以使用ChannelBuffer传统用Buffer来多次重次取数据的方式.

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
public class ReadFile
{
 public static void main(String[] args)
 {
  FileChannel fcin = null;
  try
  {
   //创建文件输入流
   FileInputStream fis = new FileInputStream("ReadFile.java");
   //创建一个FileChannel
   fcin = fis.getChannel();
   //定义一个ByteBuffer对象,用于重复取水
   ByteBuffer bbuff = ByteBuffer.allocate(1024);
   //将FileChannel中数据放入ByteBuffer中
   while( fcin.read(bbuff) != -1 )
   {
    //锁定Buffer的空白区
    bbuff.flip();        
    //创建Charset对象
    Charset charset = Charset.forName("gb2312");
    //创建解码器(CharsetDecoder)对象
    CharsetDecoder decoder = charset.newDecoder();
    //将ByteBuffer的内容转码
    CharBuffer cbuff = decoder.decode(bbuff);
    System.out.println(cbuff);
    //将Buffer初始化,为下一次取数据做准备
    bbuff.clear();
   }
  }
  catch (IOException ex)
  {
   ex.printStackTrace();
  }
  finally
  {
   try
   {
    if (fcin != null)
     fcin.close();
   }
   catch (IOException ex)
   {
    ex.printStackTrace();
   }
  }
 }
}


转载于:https://my.oschina.net/91jason/blog/313769

你可能感兴趣的:(JAVA NI/O学习-Channel)