第2章 新I/O

本章内容:

——新I/O API(NIO.2)

——Path:基于文件和目录的I/O新基础

——Files应用类和各种辅助方法

——如何实现常见的I/O应用场景

——介绍异步I/O

核心类库的变化,java.nio包内。掌握Java之前版本处理I/O的方法。

优点:

——完全取代java.io.File与文件系统的交互。

——新的异步处理类,无需手动配置线程池和其他底层并发控制。便可在后台线程中执行文件和网络I/O操作。

——引入新的Network-Channel构造方法,简化了套接字与通道的编码工作。

Java7的NIO.2 API支持目录树导航(Files.walkFileTree()),符号链接Files.isSysbolicLink(),能用一行代码读取文件属性(Files.readFileAttributes())

读取这些文件很可能打断程序的主流程。面对这一要求,在Java5/6时代可能会用java.util.concurrent中的类创建线程池和工作线程队列,再用单独后台线程读取文件。

NIO.2 API 中用AsynchronousFileChannel,不用指定工作线程或队列就可在后台读取大型文件。

NIO2为多线程文件和套接字访问的应用提供了一个简单的抽象层。IDE,应用服务器和各种流行的框架会大量应用这些特性。

将try-with-resources和NIO.2中的新API结合起来可以写出非常安全的I/O程序。

先了解新的文件系统抽象层:Path和它的辅助类。Path之上,常用的文件系统操作,复制和移动文件。

2.1 Java I/O简史

2.1.1 Java1.0-1.3

缺乏对非阻塞I/O的支持。

2.1.2 在Java1.4中引入NIO

——在Java1.4中引入非阻塞I/O

——在Java7中对非阻塞I/O进行修改

2002年发布Java1.4时新增的特性:

——为I/O操作抽象出缓冲区和通道层。

——字符集的编码和解码功能。

——提供了能够将文件映射为内存数据的接口。

——实现非阻塞I/O的能力。

——基于流行的Perl实现的正则表达式类库。

但那时对文件系统中的文件和目录处理而言支持力度还不够。那时的java.io.File类有些比较烦人的局限性。

——在不同的平台中对文件名的处理不一致。

——没有统一的文件属性模型(比如读写访问模型)

——遍历目录困难。

——不能使用平台/操作系统的特性

——不支持文件系统的非阻塞操作。

2.1.3 下一代I/O - NIO.2

NIO.2的三个主要目标:

(1)提供一个批量获取文件属性的文件系统接口。去掉和特定文件系统相关的API,还有一个用于引入标准文件系统实现的服务提供者接口。

(2)提供一个套接字和文件都能够进行异步(与轮询、非阻塞相对)I/O操作的API。

(3)完成JSR-51中定义的套接字——通道功能,包括额外对绑定,选项配置和多播数据报的支持。

2.2 文件I/O的基石:Path

NIO.2把位置(Path表示)的概念,和物理文件系统的处理(复制一个文件)分得很清楚。

物理文件系统的处理通常是由Files辅助类实现。

2.2.1 创建一个Path

Paths.get(String first, String...more)

Path listing = Path.get("/usr/bin/zip")

listing.toAbsolutePath()

2.2.2 从Path中获取信息

正在处理的路径的相关信息。

listing.getFileName()

listing.getNameCount()获取名称元素的数量

listing.getParent()

listing.getRoot()

listing.sunpath(0,2)

2.2.3 移除冗余项

Path normalizedPath = Paths.get("./Listing_2_1.java").normalize();

toRealPath()方法融合了toAbsolutePath()和normalize()两个方法,还能检测并跟随符号链接。

2.2.5 NIO.2 Path和Java已有的File类

File file = new File("../Listing_2_1.java");

Path listing = file.toPath();

listing.toAbsolutePath();

file = listing.toFile();

2.3 处理目录和目录树

2.3.1 在目录中查找文件

Path dir = Paths.get("C:\\workspace\\java7developer");

try(DirectoryStream stream = Files.newDirectoryStream(dir, "*.properties")){

for(Path entry: stream)

{

System.out.println(entry.getFileName());

}

}catch(IOException e){

System.out.println(e.getMessage());

}

过滤流中使用到的模式匹配称为glob模式匹配。

2.3.2 遍历目录树

Files.walkFileTree(Path startingDir, FileVisitor super Path> visitor);

默认实现类:SimpleFileVisitor

public class Find

{

public static void main(String[] args) throws IOException

{

Path startingDir = Paths.get("C:\\workspace\\java7developer\\src");

Files.walkFileTree(startingDir,new FindJavaVisitor());

}

private static class FindJavaVisitor extends SimpleFileVisitor

{

@Override

public FindVisitorResult visitFile(Path file,BasicFileAttributes attrs)

{

if(file.toString().endsWith(".java")){

System.out.println(file.getFileName());

}

return FindVisitorResult.CONTINUE;

}

}

}

2.4 NIO.2的文件系统I/O

Files类(复制移动删除或者处理文件的工具类),WatchService类(监视文件或目录的核心类)。

2.4.1 创建和删除文件

Path target = Paths.get("D:\\backup\\lisuxuan.txt");

Path file = Files.createFile(target);

2.4.2 文件的复制和移动

Path source = Path.get("...");

Files.copy(source,target,REPLACE_EXISTING);

Files.move(Path source,Path target,CopyOptions...);

2.4.3 文件的属性

Files.getLastModifiedTime(zip);

Files.size(zip);

Files.readAttributes(zip,"*");

2.4.4 快速读取文件

1.打开文件

用带缓冲区的读取器和写入器或者输入输出流。

Path logFile = Paths.get("/tmp/app.log");

try(BufferedReader reader = Files.newBufferedReader(logFile,StandardCharsets.UTF_8)){

String line;

while( (line = reader.readline())!= null ){

...

}

}

打开写入文件

Path logFile = Paths.get("/tmp/app.log");

try(BufferedWriter writer= Files.newBufferedWriter(logFile,StandardCharsets.UTF_8,StandardOpenOption.WRITE)){

Writer.write("hello world!");

...

}

}

设置字符编码 new String(byte[],StandardCharsets.UTF_8)

兼容过去基于java.io包的I/O:

Files.newInputStream(Path,OpenOption...)

读取全部行和全部字节的简化方法:

Path logFile = Paths.get("/tmp/app.log");

List lines = Files.readAllLines(logFile,StandardCharsets.UTF_8);

byte[] bytes = Files.readAllBytes(logFile);

2.4.5 文件修改通知

2.4.6 SeekableByteChannel

java.nio.channels.FileChannel

这个类的寻址能力让开发人员可以灵活的处理文件内容。

Path logFile = Paths.get("c:\\temp.log");

ByteBuffer buffer = ByteBuffer.allocate(1024);

FileChannel channel = FileChannel.open(logFile,StandardOpenOption.READ);

channel.read(buffer,channel.size() - 1000);

2.5 异步I/O 操作

作用:可以使用多个后台线程读写文件、套接字和通道中的数据。

AsynchronousFileChannel

AsynchronousSocketChannel

AsynchronousServerSocketChannel

2.5.1 将来式

使用java.util.concurrent.Future接口。

当你希望由主控线程发起I/O操作,并轮询等待结果时,一般都会采用将来式异步处理。

Future:用来保存异步处理的操作结果。

实现:API/JVM为执行这个任务创建了线程池和通道组。

AsynchronousFileChannel会关联线程池,它的任务是接收I/O处理事件,并分发给负责处理通道中I/O操作结果的结果处理器。跟通道中发起的I/O操作关联的结果处理器确保是由线程池中的某个线程产生的。

默认线程池是由AsynchronousChannelGroup类定义的系统属性进行配置的。

2.5.2 回调式

主线程会派一个侦察员CompletionHandler到独立的线程中执行I/O操作。这个侦查员将带着I/O操作的结果返回到主线程中,这个结果会触发自己的completed或failed方法。

在异步事件刚一成功或者失败并需要马上采取行动的时候,采用回调式。

代码清单2-9 异步I/O——回调式

============================================

try

{

Path file = Paths.get("/usr/karianna/foobar.txt");

AsynchronousFileChannel channel = AsynchronousFileChannel.open(file);

ByteBuffer buffer = ByteBuffer.allocate(100_000);

channel.read(buffer,0,buffer,new CompletionHandler()

{

public void completed(Integer result,ByteBuffer attachment)

{

System.out.println("Bytes read [" + result + "]");

}

public void failed(Throwable exception,ByteBuffer attachment)

{

System.out.println(exception.getMessage());

}

});

}catch(IOException e)

{

System.out.println(e.getMessage());

}

2.6 Socket和Channel的整合

NetworkChannel

——通道:java.nio.Channels包,表示连接到执行I/O操作的实体,比如文件和套接字,定义用于多路传输,非阻塞I/O操作的选择器。

——java.net.Socket类,

2.6.1 NetworkChannel

新接口java.nio.channels.NetworkChannel代表一个连接到网络套接字通道的映射。

package com.java7developer.chapter2;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.net.SocketAddress;

import java.net.SocketOption;

import java.net.StandardSocketOptions;

import java.nio.channels.NetworkChannel;

import java.nio.channels.spi.SelectorProvider;

import java.util.Set;

public class Listing_2_10 {

public static void main(String[] args) {

SelectorProvider provider = SelectorProvider.provider();

try {

NetworkChannel socketChannel = provider.openSocketChannel();

SocketAddress address = new InetSocketAddress(3080);

socketChannel = socketChannel.bind(address);

Set> socketOptions = socketChannel.supportedOptions();

System.out.println(socketOptions.toString());

socketChannel.setOption(StandardSocketOptions.IP_TOS, 3);

Boolean keepAlive = socketChannel

.getOption(StandardSocketOptions.SO_KEEPALIVE);

} catch (IOException e) {

System.out.println(e.getMessage());

}

}

}

2.6.2 MuticastChannel

package com.java7developer.chapter2;

import java.io.IOException;

import java.net.InetAddress;

import java.net.InetSocketAddress;

import java.net.NetworkInterface;

import java.net.StandardProtocolFamily;

import java.net.StandardSocketOptions;

import java.nio.channels.DatagramChannel;

import java.nio.channels.MembershipKey;

public class Listing_2_11 {

public static void main(String[] args) {

try {//选择网络接口

NetworkInterface networkInterface = NetworkInterface.getByName("net1");

DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET);

dc.setOption(StandardSocketOptions.SO_REUSEADDR, true);

dc.bind(new InetSocketAddress(8080));

dc.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);

InetAddress group = InetAddress.getByName("180.90.4.12");

MembershipKey key = dc.join(group, networkInterface);

} catch (IOException e) {

System.out.println(e.getMessage());

}

}

}

java修炼之道_《Java程序员修炼之道》相关推荐

  1. java属于编译_《程序员修炼之道》-读书笔记一-Java到底属于编译型语言还是解释型语言?...

    Java到底属于编译型语言还是解释型语言? 要想知道Java属于编译型语言还是解释型语言我们需要知道他们的定义和区别 定义: 编译型语言:把做好的源程序全部编译成二进制代码的可运行程序.然后,可直接运 ...

  2. java run里面定义变量_Java程序员50多道最热门的多线程和并发面试题(答案解析)...

    下面是Java程序员相关的热门面试题,你可以用它来好好准备面试. 1) 什么是线程? 线程是操作系统能够进行运算调度的最小单位,它被包含在进程之中,是进程中的实际运作单位.程序员可以通过它进行多处理器 ...

  3. java职业发展路线图_从程序员到CTO的Java技术路线图 JAVA职业规划 JAVA职业发展路线图 系统后台框架图、前端工程师技能图 B2C电子商务基础系统架构解析...

    http://zz563143188.iteye.com/blog/1877266在技术方面无论我们怎么学习,总感觉需要提升自已不知道自己处于什么水平了.但如果有清晰的指示图供参考还是非常不错的,这样 ...

  4. java学习文档_资深程序员带你深入了解JAVA知识点,实战篇,PDF文档

    JAVA 集合JAVA 集合面对浩瀚的网络学习资源,您是否为很难找到适合自己的学习资源而感到苦恼过?那么,您来对地方了.在这里我们帮助大家整理了一份适于轻松学习 Java 文章的清单.JVM 文字太多 ...

  5. java web swing 教程_好程序员Java教程解读什么是swing

    原标题:好程序员Java教程解读什么是swing 好程序员Java教程解读什么是swing,swing是java GUI应用程序,也就是java做的桌面应用.运行swing程序要求用户电脑上有java ...

  6. Java中合法的关键词_优秀程序员必须掌握的java中50个关键字

    关键字和保留字的区别 正确识别java语言的关键字(keyword)和保留字(reserved word)是十分重要的.Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表 ...

  7. java程序设计蜘蛛纸牌_介绍程序员玩纸牌

    java程序设计蜘蛛纸牌 在玩扑克,二十一点和纸牌等经典纸牌游戏时,了解程序员的历史 (Learn about programmer history while you play classic ca ...

  8. java前台界面设计_前端程序员要懂的 UI 设计知识

    前端程序员要懂的 UI 设计知识 疯狂的技术宅 前端先锋 翻译:疯狂的技术宅 作者:Per Harald Borgen 来源:freecodecamp 正文共:1401 字 预计阅读时间:5分钟 作为 ...

  9. java虚拟机 大小端_每个程序员都应当知道的“大小端”

    概述 机器是分大小端的,这对我们编程有什么影响呢?什么又是大小端呢?也许我们很多时候都不清楚,但仍然可以很好地使用电脑,或者编写代码.但我认为<圣经>里有句话说得很好,"你应该了 ...

  10. JAVA版表白神器_前端程序员表白神器

    将这段代码复制粘贴 99669999996669999996699666699666999966699666699 996999999996999999996996666996699669966996 ...

最新文章

  1. 推荐7款冷门但是非常值得推荐的windows软件
  2. pilt图像处理_详解python opencv、scikit-image和PIL图像处理库比较
  3. 华为鸿蒙搭载芯片,独立188天,荣耀50系列破冰!6nm芯片,不搭载鸿蒙
  4. 命令终端(CMD)自动补全功能 — Tab Complete 功能
  5. elf文件格式实例解析
  6. java操作阿里云的对象存储OSS
  7. 尼克老湿の面试回顾(7)
  8. git remote 命令的用法
  9. jq22扒的网站, 左右箭头图标问题
  10. word 编辑域中的汉字_神器!10秒在word中编辑复杂数学公式,不用mathtype也行!...
  11. php表格好看样式,用html和css代码实现各种表格样式的总结
  12. 关于Si24r1调试的总结
  13. 2019暑期金华集训 Day7 分治
  14. JavaScript 销毁对象
  15. Unity 最新UnityWebRequest下载,同时显示下载进度,和 显示网速,今天贴出来和大家分享
  16. 操作系统-时间片轮转调度算法
  17. Android解耦库EventBus的使用和源码分析
  18. 2.4.2 小型机状态
  19. 社区卫生医疗信息平台
  20. 求1到100之间的奇数之和、偶数之积。

热门文章

  1. Docker 基础与实战,看这一篇就够了
  2. 失去老罗,张一鸣的坚果手机多了什么?
  3. React 是如何成为跨越前端开发鸿沟的桥梁?
  4. 频遭黑客攻击的物联网,这里有妙招!
  5. 大赛响锣、Call 你来战……对面的开发者看过来!
  6. 叫板 Android 开发!跨平台应用开发神器 Flutter 又添开源插件!| 技术头条
  7. 中高级前端面试秘籍!金三银四如何直通大厂?!(长文)
  8. @扎克伯格:一句对不起,能挽回我们泄漏的数据吗?
  9. 程序员穿衣是怎么变得越来越丑的
  10. javaweb实训第二天上午——jQuery基础