JAVA NIO
简介
JavaNIO (New IO /Non Blocking IO),可以代替标准的Java IO
Java NIO 与 IO的主要区别
通道和缓冲区
Java NIO系统的核心在于:通道(channel)和缓冲区(Buffer) 通道表示打开到IO设备(文件,套接字)的连接
若需要使用NIO系统,需要获取用于连接IO设备的通道以及用于容纳数据的缓冲区. 然后操作缓冲区,对数据进行处理
简而言之 channel负责传输 Buffer 负责存储
Buffer
除了Boolean 以外,都有对应的类型缓冲区
所有缓冲区的管理方式几乎一致,通过allocate() 获取对应的缓冲区
缓冲区存储数据的两个核心方法
put():
存入数据到缓冲区中
get():
获取缓冲区中的数据
缓冲区的四个核心属性
capacity
: 容量,表示缓冲区中最大存储数据的容量,一旦声明 不能改变
position
: 表示缓冲区中正在操作数据的位置
limit
: 界限,表示缓冲区中可以操作数据的大小 limit后边的数据不能读写
mark
: 标记,表示当前position的位置 可以通过reset()恢复到mark的位置
position<=limit<=capacity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public void test() { String s = "billy"; ByteBuffer buffer = ByteBuffer.allocate(1024); System.out.println(buffer.position()); System.out.println(buffer.limit()); System.out.println(buffer.capacity()); buffer.put(s.getBytes()); System.out.println(buffer.position()); System.out.println(buffer.limit()); System.out.println(buffer.capacity()); buffer.flip(); System.out.println(buffer.position()); System.out.println(buffer.limit()); System.out.println(buffer.capacity()); byte[] bytes = new byte[buffer.limit()]; buffer.get(bytes); System.out.println(new String(bytes,0,bytes.length));
buffer.rewind(); System.out.println(buffer.position()); System.out.println(buffer.limit()); System.out.println(buffer.capacity()); buffer.get(bytes); System.out.println(new String(bytes,0,bytes.length)); buffer.clear(); System.out.println(buffer.position()); System.out.println(buffer.limit()); System.out.println(buffer.capacity()); buffer.get(bytes); System.out.println(new String(bytes,0,bytes.length)); }
|
直接缓冲区与非直接缓冲区
非直接缓冲区
: 通过allocate()方法分配缓冲区
直接缓冲区
: 通过allocateDirect() 方法分配缓冲区,就缓冲区建立在物理内存中可以提高效率,在某种情况下
通道(Channel)
通道(Channel)
: 由java.nio.channels包定义的. Channel表示IO源与目标打开的链接
Channel类似于传统中的流,只不过Channel本身不能直接访问数据,Channel只能与Buffer进行交互
通道是一个完全独立的处理器,拥有一套自己的传输方式
通道的主要实现类
java.nio.channels.channel接口:
FileChannel
SocketChannel
ServerSocketChannel
DataframChannel
获取通道:
Java针对支持通道的类提供类getChannel()方法
本地IO:
FileInputStream/FileOutputStream
RandomAccessFile
网络IO:
Socket
ServerSocket
DatagramSocket
在JDK1.7中的NIO2针对各个通道提供类静态方法open()
在JDK1.7中的NIO2的Files工具类的newByteChannel()
使用通道完成文件复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| @Test public void test1() { FileInputStream fis= null; FileOutputStream fos = null; FileChannel inc = null; FileChannel ouc = null; try { fis = new FileInputStream("src/main/resources/1.jpg"); fos = new FileOutputStream("src/main/resources/2.jpg");
inc = fis.getChannel(); ouc = fos.getChannel();
ByteBuffer buf = ByteBuffer.allocate(1024);
while(inc.read(buf)!=-1){ buf.flip(); ouc.write(buf); buf.clear();
} } catch (IOException e) { e.printStackTrace(); } finally { if (ouc!=null){
try { ouc.close(); } catch (IOException e) { e.printStackTrace(); }
} if (inc!=null){ try { inc.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos!=null){ try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis!=null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } }
}
|
使用直接缓冲区完成文件的复制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test public void test2() throws IOException { FileChannel inc = FileChannel.open(Paths.get("src/main/resources/1.jpg"), StandardOpenOption.READ); FileChannel ouc = FileChannel.open(Paths.get("src/main/resources/3.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ); MappedByteBuffer inMapBuf = inc.map(FileChannel.MapMode.READ_ONLY, 0, inc.size()); MappedByteBuffer ouMapBuf = ouc.map(FileChannel.MapMode.READ_WRITE, 0, inc.size());
byte[] dst = new byte[inMapBuf.limit()]; inMapBuf.get(dst); ouMapBuf.put(dst); inc.close(); ouc.close(); }
|
通道之间的数据传输
transferFrom()
transferTo()
1 2 3 4 5 6 7 8 9
| @Test public void test3() throws IOException { FileChannel inc = FileChannel.open(Paths.get("src/main/resources/1.jpg"), StandardOpenOption.READ); FileChannel ouc = FileChannel.open(Paths.get("src/main/resources/4.jpg"), StandardOpenOption.WRITE,StandardOpenOption.READ); inc.transferTo(0,inc.size(),ouc);
inc.close(); ouc.close(); }
|
分散与聚集
分散读取(Scatter Reads) 将通道中的数据分散到多个缓冲区中去
聚集写入(Gathering Writes) 将多个缓冲区中的数据
字符集: Charset
编码: 字符串 -> 字节数组
解码: 字节数组 -> 字符串
阻塞与非阻塞
通过NIO完成网络通信的三个核心
通道: 负责连接
SelectableChannel
- SocketChannel
- ServerSocketChannel
- DatagramChannel
- Pipe.SinkChannel
- Pipe.SourceChannel
缓冲区: 负责数据的存取
选择器: 是SelectableChannel的多路复用器.用于监控SelectableChannel的IO状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| public class TestBlockingNIO { @Test public void client() throws IOException { SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898)); FileChannel inChannel = FileChannel.open(Paths.get("src/main/resources/1.jpg"), StandardOpenOption.READ); ByteBuffer buf = ByteBuffer.allocate(1024); while(inChannel.read(buf)!=-1){ buf.flip(); sChannel.write(buf); buf.clear(); }
inChannel.close(); sChannel.close(); }
@Test public void server() throws IOException { ServerSocketChannel ssChannel = ServerSocketChannel.open(); FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); ssChannel.bind(new InetSocketAddress(9898));
SocketChannel sChannel = ssChannel.accept();
ByteBuffer buf = ByteBuffer.allocate(1024);
while(sChannel.read(buf)!=-1){ buf.flip(); outChannel.write(buf); buf.clear(); } sChannel.close(); outChannel.close(); ssChannel.close();
} }
|