[关闭]
@huangyichun 2017-08-30T15:56:22.000000Z 字数 7503 阅读 849

Java NIO

I/O


image.png-69.4kB
原来I/O是单向的,面向流的
NIO是双向的
image.png-38.7kB
image.png-148.4kB

image.png-48.7kB
image.png-136.4kB
image.png-100.2kB
image.png-110.6kB

  1. import org.junit.Test;
  2. import java.nio.ByteBuffer;
  3. /**
  4. * 一、 缓冲区(buffer):在Java NIO中负责数据的存取,缓冲区就是数组,用于存储不同数据类型的数据
  5. *
  6. * 根据数据类型不同(boolean除外),提供了相应类型的缓冲区:
  7. * ByteBuffer
  8. * CharBuffer
  9. * ShortBuffer
  10. * IntBuffer
  11. * LongBuffer
  12. * FloatBuffer
  13. * DoubleBuffer
  14. *
  15. * 上述缓存区的管理几乎一致,通过allocate()获取缓冲区
  16. *
  17. * 二、缓存区存取数据的两个核心方法
  18. * put():存入数据到缓冲区中
  19. * get(): 获取缓冲区中的数据
  20. *
  21. * 三、缓冲区中的四个核心属性
  22. *
  23. * private int mark = -1;标记:表示记录当前position的位置。可以通过reset()恢复mark位置
  24. * private int position = 0; 位置:表示缓冲区中正在操作数据的位置
  25. * private int limit; 界限:表示缓存区中可以操作数据的大小(limit)后面的数据不能进行读写
  26. * private int capacity; 容量:表示缓存区中最大存储数据容量,一旦声明不能改变
  27. *
  28. * 0 <= mark <= position <= limit <= capacity
  29. *
  30. * 四、直接缓冲区与非直接缓冲区
  31. * 非直接缓冲区:通过allocate()方法分配缓冲区,将缓冲区建立在JVM的内存中
  32. * 直接缓冲区:通过allocateDirect()方法分配直接缓冲区,将缓冲区建立在物理内存中,可以提高效率
  33. */
  34. public class TestBuffer {
  35. @Test
  36. public void test3(){
  37. //直接缓冲区
  38. ByteBuffer buf = ByteBuffer.allocateDirect(1024);
  39. System.out.println(buf.isDirect());
  40. }
  41. @Test
  42. public void test2(){
  43. String str = "abcde";
  44. ByteBuffer buf = ByteBuffer.allocate(1024);
  45. buf.put(str.getBytes());
  46. buf.flip();
  47. byte[] dst = new byte[buf.limit()];
  48. buf.get(dst, 0 ,2);//读取两个
  49. System.out.println(new String(dst,0,2));
  50. System.out.println("position: "+buf.position());
  51. //mark()标记
  52. buf.mark();
  53. buf.get(dst, 2, 2);
  54. System.out.println(new String(dst, 0, 4));
  55. System.out.println("position: "+buf.position());
  56. buf.reset();
  57. System.out.println("position: "+buf.position());
  58. if(buf.hasRemaining()){//判断缓冲区是否还有剩余的
  59. System.out.println(buf.remaining());
  60. }
  61. }
  62. @Test
  63. public void test1() {
  64. String str = "abcde";
  65. //1.分配一个指定大小的缓存区
  66. ByteBuffer buf = ByteBuffer.allocate(1024);
  67. System.out.println("------------allocate----------------");
  68. System.out.println("position: "+buf.position());
  69. System.out.println("limit: " + buf.limit());
  70. System.out.println("capacity: " + buf.capacity());
  71. System.out.println("----------------put()------------");
  72. //2.利用put()方法存入数据到缓冲区中——写数据模式
  73. buf.put(str.getBytes());
  74. System.out.println("position: "+buf.position());
  75. System.out.println("limit: " + buf.limit());
  76. System.out.println("capacity: " + buf.capacity());
  77. System.out.println("----------------flip()------------");
  78. //3.切换成读取数据模式
  79. buf.flip();
  80. System.out.println("position: "+buf.position());
  81. System.out.println("limit: " + buf.limit());
  82. System.out.println("capacity: " + buf.capacity());
  83. System.out.println("----------------get()------------");
  84. //4利用get()方法读取缓冲区的数据
  85. byte[] dst = new byte[buf.limit()];
  86. buf.get(dst);
  87. System.out.println(new String(dst, 0, dst.length));
  88. System.out.println("position: "+buf.position());
  89. System.out.println("limit: " + buf.limit());
  90. System.out.println("capacity: " + buf.capacity());
  91. System.out.println("----------------rewind()------------");
  92. //5.rewind() 可重复读数据
  93. buf.rewind();
  94. System.out.println("position: "+buf.position());
  95. System.out.println("limit: " + buf.limit());
  96. System.out.println("capacity: " + buf.capacity());
  97. System.out.println("----------------clear()------------");
  98. //6.clear():清空缓冲区,但是缓冲区中的数据依然存在,但是出于"被遗忘"状态
  99. buf.clear();
  100. System.out.println("position: "+buf.position());
  101. System.out.println("limit: " + buf.limit());
  102. System.out.println("capacity: " + buf.capacity());
  103. System.out.println((char)buf.get(1));
  104. }
  105. }

通道

image.png-96.8kB

  1. import org.junit.Test;
  2. import java.io.*;
  3. import java.nio.ByteBuffer;
  4. import java.nio.CharBuffer;
  5. import java.nio.MappedByteBuffer;
  6. import java.nio.channels.FileChannel;
  7. import java.nio.channels.FileChannel.MapMode;
  8. import java.nio.charset.CharacterCodingException;
  9. import java.nio.charset.Charset;
  10. import java.nio.charset.CharsetDecoder;
  11. import java.nio.charset.CharsetEncoder;
  12. import java.nio.file.Paths;
  13. import java.nio.file.StandardOpenOption;
  14. import java.util.Arrays;
  15. import java.util.Map;
  16. import java.util.stream.Stream;
  17. /**
  18. * 一、通道(Channel):用于源节点与目标节点的链接。在Java NIO中负责缓冲区中数据的传输
  19. * Channel本身不存储数据,因此需要配合缓冲区进行传输。
  20. * <p>
  21. * 二、通道的主要实现类
  22. * java.nio.channels.Channel接口:
  23. * |--FileChannel
  24. * |--SocketChannel
  25. * |--ServerSocketChannel
  26. * |--DatagramChannel
  27. * 三、获取通道
  28. * 1. Java支持通道的类提供了getChannel()方法
  29. * 本地IO:
  30. * FileInputStream/FileOutputStream
  31. * RandomAccessFile
  32. * <p>
  33. * 网络IO:
  34. * Socket
  35. * ServerSocket
  36. * DatagramSocket
  37. * 2. 在JDK 1.7中的NIO.2针对各个通道提供了静态方法open()
  38. * 3. 在JDK 1.7中的NIO.2的Files工具类的newByteChannel()
  39. *
  40. * 四、通道之间的数据传输
  41. * transferFrom()
  42. * transferTo()
  43. *
  44. * 五、分散(Scatter)与聚集(Gather)
  45. * 分散读取(Scattering Reads):将通道中的数据分散到多个缓冲区中
  46. * 聚集写入(Gathering Writers):将多个缓冲区中的数据聚集到通道中
  47. *
  48. * 六、字符集:Charset
  49. * 编码: 字符串——>字节数组
  50. * 解码: 字节数组——>字符串
  51. *
  52. */
  53. public class TestChannel {
  54. //字符集
  55. @Test
  56. public void test7() throws CharacterCodingException {
  57. Charset cs1 = Charset.forName("GBK");
  58. //获取编码器
  59. CharsetEncoder ce = cs1.newEncoder();
  60. //获取解码器
  61. CharsetDecoder cd = cs1.newDecoder();
  62. CharBuffer cBuf = CharBuffer.allocate(1024);
  63. cBuf.put("尚硅谷威武!");
  64. cBuf.flip();//切换读
  65. //编码
  66. ByteBuffer byteBuffer = ce.encode(cBuf);
  67. for(int i=0; i<cBuf.limit()*2; i++){
  68. System.out.println(byteBuffer.get());
  69. }
  70. //解码
  71. byteBuffer.flip();
  72. CharBuffer cBuf2 = cd.decode(byteBuffer);
  73. System.out.println(cBuf2.toString());
  74. }
  75. @Test
  76. public void test6(){
  77. Map<String, Charset> map = Charset.availableCharsets();
  78. map.forEach((x,y)->{
  79. System.out.println(x+"="+y);
  80. });
  81. }
  82. //分散和聚集
  83. @Test
  84. public void test5() throws IOException {
  85. RandomAccessFile raf = new RandomAccessFile("学习清单.txt","rw");
  86. //1.获取通道
  87. FileChannel channel = raf.getChannel();
  88. //2.分配指定大小的缓冲区
  89. ByteBuffer buf1 = ByteBuffer.allocate(100);
  90. ByteBuffer buf2 = ByteBuffer.allocate(1024);
  91. //3.分散读取
  92. ByteBuffer[] bufs = {buf1, buf2};
  93. channel.read(bufs);
  94. Arrays.stream(bufs).forEach(ByteBuffer::flip);//转换成读模式
  95. System.out.println(new String(bufs[0].array(),0, bufs[0].limit()));
  96. System.out.println("------------------------");
  97. System.out.println(new String(bufs[1].array(), 0, bufs[1].limit()));
  98. //4.聚集写入
  99. RandomAccessFile raf2 = new RandomAccessFile("2.txt","rw");
  100. FileChannel channel2 = raf2.getChannel();
  101. channel2.write(bufs);
  102. channel.close();
  103. channel2.close();
  104. }
  105. //通道之间的数据传输(直接缓冲区,内存映射文件)
  106. @Test
  107. public void test4() throws IOException {
  108. FileChannel inChannel = FileChannel.open(Paths.get("E:/1.zip"),StandardOpenOption.READ);
  109. FileChannel outChannel = FileChannel.open(Paths.get("E:/2.zip"),StandardOpenOption.READ, StandardOpenOption.WRITE,StandardOpenOption.CREATE);
  110. // inChannel.transferTo(0, inChannel.size(), outChannel);
  111. outChannel.transferFrom(inChannel, 0, inChannel.size());
  112. inChannel.close();
  113. outChannel.close();
  114. }
  115. //3. I/O操作
  116. @Test
  117. public void test3() throws IOException { //9755
  118. long start = System.currentTimeMillis();
  119. FileInputStream fis = new FileInputStream("E:/1.zip");
  120. FileOutputStream fos = new FileOutputStream("E:/2.zip");
  121. BufferedInputStream bufis = new BufferedInputStream(fis);
  122. byte[] bts = new byte[1024];
  123. while(bufis.read(bts) != -1){
  124. fos.write(bts);
  125. }
  126. bufis.close();
  127. fis.close();
  128. fos.close();
  129. long end = System.currentTimeMillis();
  130. System.out.println("耗费时间为:" + (end-start));
  131. }
  132. //2.使用直接缓冲区完成文件复制(内存映射文件)
  133. @Test
  134. public void test2() throws IOException {//2457
  135. long start = System.currentTimeMillis();
  136. FileChannel inChannel = FileChannel.open(Paths.get("E:/1.zip"), StandardOpenOption.READ);
  137. FileChannel outChannel = FileChannel.open(Paths.get("E:/2.zip"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);
  138. //内存映射文件
  139. MappedByteBuffer inMappedBuf = inChannel.map(MapMode.READ_ONLY, 0, inChannel.size());
  140. MappedByteBuffer outMappedBuf = outChannel.map(MapMode.READ_WRITE, 0, inChannel.size());
  141. //直接对缓冲区对数据的读写操作
  142. byte[] dst = new byte[inMappedBuf.limit()];
  143. inMappedBuf.get(dst);
  144. outMappedBuf.put(dst);
  145. inChannel.close();
  146. outChannel.close();
  147. long end = System.currentTimeMillis();
  148. System.out.println("耗费时间为:" + (end-start));
  149. }
  150. //1.利用通道完成文件的复制(非直接缓冲区)
  151. @Test
  152. public void test1() throws IOException {//9942
  153. long start = System.currentTimeMillis();
  154. FileInputStream fis = new FileInputStream("E:/1.zip");
  155. FileOutputStream fos = new FileOutputStream("E:/2.zip");
  156. //获取通道
  157. FileChannel inChannel = fis.getChannel();
  158. FileChannel outChannel = fos.getChannel();
  159. //分配指定大小的缓存区
  160. ByteBuffer buf = ByteBuffer.allocate(1024);
  161. //将通道中的数据存入缓冲区中
  162. while (inChannel.read(buf) != -1) {
  163. //将缓冲区中的数据写入通道中
  164. buf.flip(); //切换成读取数据的模式
  165. outChannel.write(buf);
  166. buf.clear();//清空缓冲区
  167. }
  168. outChannel.close();
  169. inChannel.close();
  170. fos.close();
  171. fis.close();
  172. long end = System.currentTimeMillis();
  173. System.out.println("耗费时间为:" + (end-start));
  174. }
  175. }

NIO非阻塞式网络编程

image.png-60.6kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注