[java] java NIO 基础
JAVA NIO中一个比较重要的Buffer(缓冲区)类:
以下是Java NIO里关键的Buffer实现:
- ByteBuffer
- CharBuffer
- DoubleBuffer
- FloatBuffer
- IntBuffer
- LongBuffer
- ShortBuffer
- MappedByteBuffer
这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double 和 char。
下图是该类部分类,实现类的大部分方法的类图。

使用NIO对文件进行写,复制操作:
//文件复制 public static void copyFile1(File src,File dest)throws Exception{ FileInputStream fis = new FileInputStream(src); FileChannel from = fis.getChannel(); FileOutputStream fos = new FileOutputStream(dest); FileChannel to =fos.getChannel(); //通道直接进行文件复制 to.transferFrom(from,0,from.size()); fis.close(); fos.close(); } /** * 向文件中写入内容 * @param file * @throws Exception */ public static void write(File file ) throws Exception{ FileOutputStream outs = new FileOutputStream(file); //获取通道 FileChannel fileChannel = outs.getChannel(); ByteBuffer byteBuffer = ByteBuffer.allocate(48); String txt = "写进内容: java NIO 操作" ; //将内容写进缓冲区 byteBuffer.put(txt.getBytes()); byteBuffer.flip(); fileChannel.write(byteBuffer); //关闭 fileChannel.close(); outs.close(); }
为了理解Buffer的工作原理,需要熟悉它的三个属性:
- capacity
- position
- limit
position和limit的含义取决于Buffer处在读模式还是写模式。不管Buffer处在什么模式,capacity的含义总是一样的。
作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。
capacity
作为一个内存块,Buffer有一个固定的大小值,也叫“capacity”.你只能往里写capacity个byte、long,char等类型。一旦Buffer满了,需要将其清空(通过读数据或者清除数据)才能继续写数据往里写数据。
position
当你写数据到Buffer中时,position表示当前的位置。初始的position值为0.当一个byte、long等数据写到Buffer后, position会向前移动到下一个可插入数据的Buffer单元。position最大可为capacity – 1.
当读取数据时,也是从某个特定位置读。当将Buffer从写模式切换到读模式,position会被重置为0. 当从Buffer的position处读取数据时,position向前移动到下一个可读的位置。
limit
在写模式下,Buffer的limit表示你最多能往Buffer里写多少数据。 写模式下,limit等于Buffer的capacity。
当切换Buffer到读模式时, limit表示你最多能读到多少数据。因此,当切换Buffer到读模式时,limit会被设置成写模式下的position值。换句话说,你能读到之前写入的所有数据(limit被设置成已写数据的数量,这个值在写模式下就是position).
ByteBuffer 的几个主要方法源码:
1.put
写数据到Buffer有两种方式:
- 从Channel写到Buffer。
- 通过Buffer的put()方法写到Buffer里。
从Channel写到Buffer的例子
int bytesRead = inChannel.read(buf);
通过put方法写Buffer的例子:
buf.put(512);
put方法有很多版本,允许你以不同的方式把数据写入到Buffer中。例如, 写到一个指定的位置,或者把一个字节数组写入到Buffer。
/** * Relative bulk <i>put</i> method <i>(optional operation)</i>. * * <p> This method transfers the bytes remaining in the given source * buffer into this buffer. If there are more bytes remaining in the * source buffer than in this buffer, that is, if * <tt>src.remaining()</tt> <tt>></tt> <tt>remaining()</tt>, * then no bytes are transferred and a {@link * BufferOverflowException} is thrown. * * <p> Otherwise, this method copies * <i>n</i> = <tt>src.remaining()</tt> bytes from the given * buffer into this buffer, starting at each buffer's current position. * The positions of both buffers are then incremented by <i>n</i>. * * <p> In other words, an invocation of this method of the form * <tt>dst.put(src)</tt> has exactly the same effect as the loop * * <pre> * while (src.hasRemaining()) * dst.put(src.get()); </pre> * * except that it first checks that there is sufficient space in this * buffer and it is potentially much more efficient. </p> * * @param src * The source buffer from which bytes are to be read; * must not be this buffer * * @return This buffer * * @throws BufferOverflowException * If there is insufficient space in this buffer * for the remaining bytes in the source buffer * * @throws IllegalArgumentException * If the source buffer is this buffer * * @throws ReadOnlyBufferException * If this buffer is read-only */ public ByteBuffer put(ByteBuffer src) { if (src == this) throw new IllegalArgumentException(); int n = src.remaining(); if (n > remaining()) throw new BufferOverflowException(); for (int i = 0; i < n; i++) put(src.get()); return this; }
2.flip
flip方法将Buffer从写模式切换到读模式。调用flip()方法会将position设回0,并将limit设置成之前position的值。
换句话说,position现在用于标记读的位置,limit表示之前写进了多少个byte、char等 —— 现在能读取多少个byte、char等。
/** * Flips this buffer. The limit is set to the current position and then * the position is set to zero. If the mark is defined then it is * discarded. * * <p> After a sequence of channel-read or <i>put</i> operations, invoke * this method to prepare for a sequence of channel-write or relative * <i>get</i> operations. For example: * * <blockquote><pre> * buf.put(magic); // Prepend header * in.read(buf); // Read data into rest of buffer * buf.flip(); // Flip buffer * out.write(buf); // Write header + data to channel</pre></blockquote> * * <p> This method is often used in conjunction with the {@link * java.nio.ByteBuffer#compact compact} method when transferring data from * one place to another. </p> * * @return This buffer */ public final Buffer flip() { limit = position; position = 0; mark = -1; return this; }
3.clear
/** * Clears this buffer. The position is set to zero, the limit is set to * the capacity, and the mark is discarded. * * <p> Invoke this method before using a sequence of channel-read or * <i>put</i> operations to fill this buffer. For example: * * <blockquote><pre> * buf.clear(); // Prepare buffer for reading * in.read(buf); // Read data</pre></blockquote> * * <p> This method does not actually erase the data in the buffer, but it * is named as if it did because it will most often be used in situations * in which that might as well be the case. </p> * * @return This buffer */ public final Buffer clear() { position = 0; limit = capacity; mark = -1; return this; }

浙公网安备 33010602011771号