最重要的四种Channel

  • FileChannel 文件通道,用于文件的读写
  • SocketChannel tcp连接,客户端服务器都能用
  • ServerSocketChannel tcp连接,用于服务器
  • DatagramChannel UDP连接


FileChannel

FileChannel 只能工作在阻塞模式下

获取FileChannel:通过输入输出流或者RandomAccessFile 获取

  • 通过 FileInputStream 获取的 channel 只能读
  • 通过 FileOutputStream 获取的 channel 只能写
  • 通过 RandomAccessFile 是否能读写根据构造 RandomAccessFile 时的读写模式决定


关闭FileChannel**:
channel 必须关闭,不过调用了 FileInputStream、FileOutputStream 或者 RandomAccessFile 的 close 方法会间接地调用 channel 的 close 方法

强制写入
操作系统出于性能的考虑,会将数据缓存,不是立刻写入磁盘。可以调用 force(true) 方法将文件内容和元数据(文件的权限等信息)立刻写入磁盘

  1. public static void copyFile1(String sourceFilePath,String targetFilePath){
  2. var start = System.currentTimeMillis();
  3. try {
  4. @Cleanup FileInputStream fis = new FileInputStream(sourceFilePath);
  5. @Cleanup FileOutputStream fos = new FileOutputStream(targetFilePath);
  6. @Cleanup FileChannel inChannel = fis.getChannel();
  7. @Cleanup FileChannel outChannel = fos.getChannel();
  8. ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
  9. while(inChannel.read(buffer) != -1){
  10. //切换为读模式
  11. buffer.flip();
  12. outChannel.write(buffer);
  13. //清除buffer 变为写模式
  14. buffer.clear();
  15. }
  16. //强制刷盘
  17. outChannel.force(true);
  18. } catch (FileNotFoundException e) {
  19. System.out.println(" 源文件路径:" + sourceFilePath + "复制源文件不存在");
  20. } catch (IOException e) {
  21. System.out.println("文件复制异常" + e.getMessage());
  22. }
  23. var end = System.currentTimeMillis();
  24. System.out.println("耗时:" + (end - start));
  25. }
  26. /**
  27. *
  28. * @param sourceFilePath
  29. * @param targetFilePath
  30. */
  31. public static void copyFile2(String sourceFilePath,String targetFilePath){
  32. var start = System.currentTimeMillis();
  33. try {
  34. FileChannel sourceChannle = new FileInputStream(sourceFilePath).getChannel();
  35. FileChannel targetChannle = new FileOutputStream(targetFilePath).getChannel();
  36. long size = sourceChannle.size();
  37. //表示还剩余多少字节没有传输
  38. long left = size;
  39. while (left > 0){
  40. //底层会使用操作系统的零拷贝,一次最多传输2g的数据
  41. left -= sourceChannle.transferTo(size - left,sourceChannle.size(),targetChannle);
  42. }
  43. targetChannle.force(true);
  44. } catch (FileNotFoundException e) {
  45. e.printStackTrace();
  46. } catch (IOException e) {
  47. e.printStackTrace();
  48. }
  49. var end = System.currentTimeMillis();
  50. System.out.println("耗时:" + (end - start));
  51. }

SocketChannel

NIO中涉及网元连接的通道有两个,一个是SocketChannel负责连接传输,另一个ServerSocketChannel负责连接的监听

ServerSocketChannel用于服务端,而SocketChannel同时应用于服务端和客户端,对于一个连接两端都有一个负责传输的SocketChannel传输通道。