Android开发进阶之NIO非阻塞包(二)

有关Android NIO我们主要分为三大类,ByteBufferFileChannelSocketChannel。由于篇幅原因今天Android123只对前两个做说明。NIO和传统的I/O比较大的区别在于传输方式非阻塞,一种基于事件驱动的模式,将会使方法执行完后立即返回,传统I/O主要使用了流Stream的方式,而在New I/O中,使用了字节缓存ByteBuffer来承载数据。

   ByteBuffer位于java.nio包中,目前提供了Java基本类型中除Boolean外其他类型的缓冲类型,比如ByteBufferDoubleBufferFloatBufferIntBufferLongBufferShortBuffer  。同时还提供了一种更特殊的映射字节缓冲类型MappedByteBuffer。在传统IO的输入输出流中,InputStream中只提供了字节型或字节数组的访问对应NIO就是ByteBuffer,但是处理传统的DataInputStreamint等类型,就是IntBuffer,但是缓冲类型并没有提供UTF这样的类型处理,所以我们仍然需要使用ByteBuffer处理字符串,但是NIO提供了一个封装的类在java.nio.charset包中,通过字符的编码CharsetEncoder和解码CharsetDecoder类来处理字符串,同时这些类可以方便转换编码比如GBKUTF等等。

  一、ByteBuffer

  1) 实例化

  直接使用ByteBuffer类的静态方法static ByteBuffer allocate(int capacity) static ByteBuffer allocateDirect(int capacity)  这两个方法来分配内存空间,两种方法的区别主要是后者更适用于繁复分配的字节数组。而 put(ByteBuffer src) 可以从另一个ByteBuffer中构造,也可以通过wrap方法从byte[]中构造,具体参考下面的类型转化内容。

  2) 类型转化

   ByteBuffer可以很好的和字节数组byte[]转换类型,通过执行ByteBuffer类的final byte[]  array() 方法就可以将ByteBuffer转为byte[]。从byte[]来构造ByteBuffer可以使用wrap方法,目前Android或者说Java提供了两种重写方法,比如为static ByteBuffer  wrap(byte[] array)  static ByteBuffer  wrap(byte[] array, int start, int len)  ,第二个重载方法中第二个参数为从array这个字节数组的起初位置,第三个参数为array这个字节数组的长度。

  3) ByteBuffer中添加元素

  目前ByteBuffer提供了多种put重写类型来添加,比如put(byte b) putChar(char value) putFloat(float value) 等等,需要注意的是,按照Java的类型长度,一个byte1字节,一个char类型是2字节,一个floatint4字节,一个long则为8字节,和传统的C++有些区别。所以内部的相关位置也会发生变化,同时每种方法还提供了定位的方法比如ByteBuffer  put(int index, byte b) 

  4) ByteBuffer中获取元素

  同上面的添加想法,各种put被换成了get,比如byte  get()  float  getFloat()  ,当然了还提供了一种定位的方式,比如double  getDouble(int index) 

  5) ByteBuffer中字节顺序

  对于Java来说默认使用了BIG_ENDIAN方式存储,和C正好相反的,通过

  final ByteOrder  order() 返回当前的字节顺序。

  final ByteBuffer  order(ByteOrder byteOrder)  设置字节顺序,ByteOrder类的值有两个定义,比如LITTLE_ENDIANBIG_ENDIAN,如果使用当前平台则为ByteOrder.nativeOrder()Android中则为 BIG_ENDIAN,当然如果设置为order(null) 则使用LITTLE_ENDIAN

  二、FileChannel

   NIO中除了Socket外,还提供了File设备的通道类,FileChannel位于java.nio.channels.FileChannel包中,在Android SDK文档中我们可以方便的找到,对于文件复制我们可以使用ByteBuffer方式作为缓冲,比如

  String infile = "/sdcard/cwj.dat";
  String outfile = "/sdcard/android123-test.dat";

    FileInputStream fin = new FileInputStream( infile );
    FileOutputStream fout = new FileOutputStream( outfile );

    FileChannel fcin = fin.getChannel();
    FileChannel fcout = fout.getChannel();

    ByteBuffer buffer = ByteBuffer.allocate( 1024 ); //分配1KB作为缓冲区

    while (true) {
    buffer.clear(); //
每次使用必须置空缓冲区

      int r = fcin.read( buffer );

      if (r==-1) {
        break;
      }

   buffer.flip(); //写入前使用flip这个方法

      fcout.write( buffer );
    }

   flipclear这两个方法是java.nio.Buffer包中,ByteBuffer的父类是从Buffer类继承而来的,这点Android123要提醒大家看Android SDK文档时注意Inherited Methods,而JDK的文档就比较直接了,同时复制文件使用FileChanneltransferTo(long position, long count, WritableByteChannel target) 这个方法可以快速的复制文件,无需自己管理ByteBuffer缓冲区。明天Android开发网介绍NIO主要的Socket相关的内容。

 

原文地址:https://www.cnblogs.com/cpcpc/p/2123008.html