Java NIO2

http://developer.51cto.com/art/200911/165703.htm
整理自《Pro Java 7 NIO.2》
1 Path类
1.1 Path类介绍
1.2 定义一个Path
1.3 获取Path属性
1.4 转换Path
1.5 拼接Path
1.6 在两个位置间转换Path
1.7 比较两个Path
1.8 迭代Path中的Name元素
2 元文件属性
2.1 NIO2支持的视图
2.2 检查特定文件系统支持的视图
2.3 Basic视图
2.3.1 readAttributes()获取所有的属性
2.3.2 获取单个属性
2.3.3 更新属性
2.4 Dos视图
2.5 FileOwner视图
2.5.1 使用Files.setOwner设置owner
2.5.2 使用FileOwnerAttributeView.setOwner()设置owner
2.5.3 使用Files.setAttribute()设置owner
2.5.4 使用FileOwnerAttributeView.getOwner()获取owner
2.5.5使用Files.getAttribute()获取owner
2.6 POSIX视图
2.6.1 POSIX Permissions
2.6.2 POSIX Group Owner
2.7 ACL视图
2.7.1 使用Files.getFileAttributeView()获取ACL
2.7.2 使用Files.getAttribute()获取ACL
2.7.3 Read ACL Entries
2.8 File Store属性
2.8.1 获取所有的File Store属性
2.8.2 获取文件所在的File Store的属性
2.9 用户自定义的文件属性
2.9.1 是否支持用户自定义属性
2.9.2用户自定义属性的操作
3 管理软链接和硬链接
3.1 链接简介
3.2 通过命令行创建链接
3.3 创建软链接
3.4 创建硬链接
3.5 检查软链接
3.6 定位链接目标
3.7 检测链接和文件是否相同
4 文件和目录
4.1 文件和目录的检测方法
4.2 创建读目录
4.3 创建读写文件
4.4 创建临时目录和文件
5 递归操作 Walks 
          5.1FileVisitor接口
          5.2 SimpleFileVisitor类
          5.3 开启递归旅程
          5.4 常用Walk
               5.4.1 查询Walk
               5.4.2 删除Walk
               5.4.3 复制Walk
               5.4.4 Move Walk
6 Watch Service API
          6.1 Watch Service API类
          6.2 实现Watch Service
          6.3 使用Watch Service的其他例子
               6.3.1 监控目录树
               6.3.2 检索Video Camera
               6.3.3 检索Printer Tray System
7 随机存取文件
          7.1 ByteBuffer简介
          7.2 Channel简介
          7.3 使用SeekableByteChannel
          7.4 使用FileChannel
               7.4.1 文件直接映射内存
               7.4.2 锁Channel文件
               7.4.3 使用FileChannel复制文件
8 Socker  API
          8.1 NetworkChannel简介
               8.1.1 Socket选项
          8.2 TCP应用程序
               8.2.1 阻塞和非阻塞机制
               8.2.2阻塞TCP服务端
               8.2.3 阻塞TCP客户端
               8.2.4 测试
               8.2.5 非阻塞的TCP/IP程序
          8.3 UDP应用程序
               8.3.1 UDP服务端
               8.3.2 无连接的UDP客户端
               8.3.3 面向连接的UDP客户端
               8.3.4 多播
9异步Channel API     
          9.1 同步I/O和异步I/O
          9.2 异步I/O总览
               9.2.1 Pending Result and the Future Class
               9.2.2 Complete Result and the CompletionHandler Interface 
               9.2.3 Types of Asynchronous Channels
               9.2.4 Groups
               9.2.5 ByteBuffer注意事项
               9.2.6 ExecutorService API
          9.3 开发异步应用
               9.3.1 Asynchronous File Channel例子
               9.3.2 Asynchronous Channel Sockets 例子
10注意事项
          10.1 Refactoring java.io.File code
          10.2 使用ZIP file system provide
          10.3 Considerations about custom file system providers
          10.4 有用的方法 
  • 1 Path类
       JDK7引入了NIO.2 API,它是JSR203:More New I/O APIs for the Java Platform的实现,主要涉及抽象类java.nio.file.Path.Path类支持两种类型的操作:句法操作(syntactic operations,大多数涉及到path的都不用访问文件系统,只是内存中的逻辑操作)和有关path的文件操作。
 
  • 1.1 Path类介绍
      文件系统可以通过java.nio.file.FileSystems静态类(用来获取java.nio.file.FileSystem实例),FileSystems类包括3个newFileSystem方法、用于获取当前JVM默认的文件系统的getDefault()静态方法和 通过URI获取文件系统的getFileSystem(URI uri)静态方法。
     Path类是java.io.File的升级版本。 
     对比下两者之间操作上的差异:
import java.io.File;

File file = new File("index.html");
NIO.2版本 
import java.nio.file.Path;
import java.nio.file.Paths;

Path path = Paths.get("index.html");

  • 1.2 定义一个Path
Paths类只包含两个方法:
public static Path get(String first, String ... more) {
        return FileSystems .getDefault().getPath (first , more) ;
}

public static Path get(URI uri) {
        String scheme =  uri. getScheme() ;
        if (scheme == null)
            throw new IllegalArgumentException ("Missing scheme");

        // check for default provider to avoid loading of installed providers
        if (scheme .equalsIgnoreCase ("file" ))
            return FileSystems.getDefault (). provider() .getPath (uri );

        // try to find provider
        for (FileSystemProvider provider : FileSystemProvider.installedProviders ()) {
            if (provider .getScheme (). equalsIgnoreCase(scheme )) {
                return provider. getPath( uri) ;
            }
        }

        throw new FileSystemNotFoundException ("Provider \"" + scheme + "\" not installed" );
}

定义一个绝对路径Path
Path path = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
Path path = Paths.get("C:", "rafaelnadal/tournaments/2009", "BNP.txt");
Path path = Paths.get("C:", "rafaelnadal", "tournaments", "2009", "BNP.txt");  

Define a Path Relative to the File Store Root
Path path = Paths.get("/rafaelnadal/tournaments/2009/BNP.txt");
Path path = Paths.get("/rafaelnadal","tournaments/2009/BNP.txt");
注意和下面当前工作目录的Path的区别,需要加上系统的文件分隔符。File Store理解为当前代码所在的盘符或者挂载点、卷。

定义一个当前工作目录的相对路径的Path
Path path = Paths.get("rafaelnadal/tournaments/2009/BNP.txt");
Path path = Paths.get("rafaelnadal","tournaments/2009/BNP.txt");

Define a Path Using Shortcuts
Path noNormalize = Paths.get("C:/rafaelnadal/tournaments/./2009/dummy/../BNP.txt");
Path normalize = Paths.get("C:/rafaelnadal/tournaments/./2009/dummy/../BNP.txt").normalize();
normalize的区别在于是否会解析.和..。
C:\rafaelnadal\tournaments\.\2009\dummy\..\BNP.txt
C:\rafaelnadal\tournaments\2009\BNP.txt

Define a Path from a URI
import java.net.URI;

Path path = Paths.get(URI.create("file:///rafaelnadal/tournaments/2009/BNP.txt"));
Path path = Paths.get(URI.create("file:///C:/rafaelnadal/tournaments/2009/BNP.txt"));

Define a Path using FileSystems.getDefault().getPath() Method
import java.nio.file.FileSystems;

Path path = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/2009", "BNP.txt");
Path path = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/2009/BNP.txt");
Path path = FileSystems.getDefault().getPath("rafaelnadal/tournaments/2009", "BNP.txt");
Path path = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/./2009","BNP.txt").normalize();

Get the Path of the Home Directory
Path path = Paths.get(System.getProperty("user.home"), "downloads", "game.exe");

  • 1.3 获取Path属性
Path path = Paths.get("C:/rafaelnadal/tournaments/./2009/dummy/../BNP.txt") ;
获取文件或目录名
System.out.println("The file/directory indicated by path: " + path.getFileName());
//output: BNP.txt

获取Path Root
System.out.println("Root of this path: " + path.getRoot());
//output: C:\

获取Path 父目录
System.out.println("Parent: " + path.getParent());
//output: C:\rafaelnadal\tournaments\2009

获取Path名字元素
System.out.println("Number of name elements in path: " + path.getNameCount());
//output: 4 

for (int i = 0; i < path.getNameCount(); i++) {
       System.out.println("Name element " + i + " is: " + path.getName(i));
}
//output: rafaelnadal  tournaments   2009   BNP.txt

Get a Path Subpath
System.out.println("Subpath (0,3): " + path.subpath(0, 3));
//output: rafaelnadal\tournaments\2009

  • 1.4 转换Path
Path path = Paths.get("/rafaelnadal/tournaments/2009", "BNP.txt");
Path转换为字符串
System.out.println("Path to String: " + path.toString());
Path to String: \rafaelnadal\tournaments\2009\BNP.txt


Path转换为URI
可以在web页面浏览的路径。
System.out.println("Root of this path: " + path.toUri());
Root of this path: file:///D:/rafaelnadal/tournaments/2009/BNP.txt

Path转换绝对路径
 System.out.println("Path to absolute path: " + path.toAbsolutePath().toString());
Path to absolute path: D:\rafaelnadal\tournaments\2009\BNP.txt

Path转换为实际的路径
如果Path不存在或无访问权限,会报异常。
try {
     Path real_path = path.toRealPath(LinkOption.NOFOLLOW_LINKS);  // 忽略符号链接
     System.out.println("Path to real path: " + real_path);
} catch (NoSuchFileException e) {
     System.err.println(e);
} catch (IOException e) {
     System.err.println(e);
}
java.nio.file.NoSuchFileException 

Path转换为File
File path_to_file = path.toFile();
Path file_to_path = path_to_file.toPath();
System.out.println("Path to file name: " + path_to_file.getName());
System.out.println("File to path: " + file_to_path.toString());
Path to file name: BNP.txt
File to path: \rafaelnadal\tournaments\2009\BNP.txt


  • 1.5 拼接Path
//define the fixed path
Path base = Paths.get("C:/rafaelnadal/tournaments/2009");

//resolve BNP.txt file
Path path_1 = base.resolve("BNP.txt");
System.out.println(path_1.toString());
//output: C:\rafaelnadal\tournaments\2009\BNP.txt 

resolveSibling相当于分离出父目录,下面的例子用户替换文件名。 
//define the fixed path
Path base = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");
//resolve sibling AEGON.txt file
Path path = base.resolveSibling("AEGON.txt");
System.out.println(path.toString());
//output: C:\rafaelnadal\tournaments\2009\AEGON.txt
  • 1.6在两个位置间转换Path
两个位置必须都包含root元素。即必须能够通过.或者..互相访问。
Path path01 = Paths.get("/tournaments/2009/BNP.txt");
Path path02 = Paths.get("/tournaments/2011");

Path path01_to_path02 = path01.relativize(path02);
System.out.println(path01_to_path02);
//output: ..\..\2011

Path path02_to_path01 = path02.relativize(path01);
System.out.println(path02_to_path01);
//output: ..\2009\BNP.txt
  • 1.7 比较两个Path
Path path01 = Paths.get("/rafaelnadal/tournaments/2009/BNP.txt");
Path path02 = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");
if(path01.equals(path02)){  // 不会检查文件是否存在,有些平台区分大小写,和Object.equals()类似。
     System.out.println("The paths are equal!");
} else {
     System.out.println("The paths are not equal!"); //true
}
在equals返回false之后,调用 Files.isSameFile检查。
try {
     boolean check = Files.isSameFile(path01, path02);
     if(check){
          System.out.println("The paths locate the same file!"); //true
     } else {
          System.out.println("The paths does not locate the same file!");
     }
} catch (IOException e) {
     System.out.println(e.getMessage());
}

由于Path类实现了Comparable接口,所以可以使用compareTo方法比较两个Path。
int compare = path01.compareTo(path02);
System.out.println(compare);  //output: 24

boolean sw = path01.startsWith("/rafaelnadal/tournaments");
boolean ew = path01.endsWith("BNP.txt");
System.out.println(sw); //output: true
System.out.println(ew); //output: true

  • 1.8迭代Path中的Name元素
由于实现了Iterator接口,所以可以使用显式的Iterator或者如下的foreach方法迭代获取Path中的Name。
Path path = Paths.get("C:", "rafaelnadal/tournaments/2009", "BNP.txt");
for (Path name : path) {
     System.out.println(name);
}
输出:
rafaelnadal
tournaments
2009
BNP.txt

  • 2 元文件属性
  • 2.1 NIO2支持的视图
视图说明
BasicFileAttributeView所有文件系统都支持的属性,属性视图名是basic
DosFileAttributeView支持DOS属性,视图名dos,扩展basic
PosixFileAttributeView支持POSIX (Portable Operating System Interface for Unix)属性,视图名posix,扩展basic
FileOwnerAttributeView支持file owner概念的文件系统,视图名为owner
AclFileAttributeViewThis view supports reading or updating a file’s ACL. The NFSv4 ACL model is supported. The attribute view name is acl.
UserDefinedFileAttributeView支持用户自定义属性,视图名为user

  • 2.2检查特定文件系统支持的视图
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.util.Set;

FileSystem fs = FileSystems.getDefault();
Set<String> views = fs.supportedFileAttributeViews();
for (String view : views) {
     System.out.println(view);
}
Windows7支持下面5种视图:
acl
basic
owner
user
dos

FileStore分区和挂载点支持:
import java.nio.file.FileStore;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.attribute.BasicFileAttributeView;

FileSystem fs = FileSystems.getDefault();
for (FileStore store : fs.getFileStores()) {
     boolean supported = store.supportsFileAttributeView(BasicFileAttributeView.class);
     System.out.println(store.name() + " ---" + supported);
}
OS ---true
Data ---true
Lenovo_Recovery ---true

特定文件所支持的元文件属性
import java.io.IOException;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     FileStore store = Files.getFileStore(path);
     boolean supported = store.supportsFileAttributeView("basic");
     System.out.println(store.name() + " ---" + supported);
} catch (IOException e) {
     System.err.println(e);
}

  • 2.3 Basic视图
  • 2.3.1 readAttributes()获取所有的属性
BasicFileAttributes attr = null;
 Path pathView = Paths.get("C:/", "test1.ini") ;
try {
   attr = Files.readAttributes(pathView , BasicFileAttributes.class);
catch(IOException e) {
   System.err.println(e);
}
System.out.println("File size: " + attr. size()) ;
System.out.println("File creation time: " + attr.creationTime()) ;
System.out.println("File was last accessed at: " + attr.lastAccessTime()) ;
System.out.println("File was last modified at: " + attr.lastModifiedTime()) ;
System.out.println("Is directory? " + attr.isDirectory()) ;
System.out.println("Is regular file? " + attr.isRegularFile()) ;
System.out.println("Is symbolic link? " + attr.isSymbolicLink()) ;
System.out.println("Is other? " + attr.isOther()) ;

File size: 506
File creation time: 2015-03-02T04:03:36.205917Z
File was last accessed at: 2015-03-02T08:08:02.034943Z
File was last modified at: 2015-03-02T08:08:02.034943Z
Is directory? false
Is regular file? true
Is symbolic link? false
Is other? false

  • 2.3.2 获取单个属性
try {
     long size = (Long)Files.getAttribute(pathView, "basic:size", LinkOption.NOFOLLOW_LINKS);
     System.out.println("Size: " + size) ;
catch(IOException e) {
     System.err.println(e);
}

The generally accepted form for retrieving a single attribute is [view-name:]attribute-name. The view-name is basic.
•  lastModifiedTime
•  lastAccessTime
•  creationTime
•  size
•  isRegularFile
•  isDirectory
•  isSymbolicLink
•  isOther
•  fileKey
  • 2.3.3 更新属性
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
long time = System.currentTimeMillis();
FileTime fileTime = FileTime.fromMillis(time);
try {
     Files.getFileAttributeView(path,
     BasicFileAttributeView.class).setTimes(fileTime, fileTime, fileTime); //3个参数分别是lastModifiedTime,lastAccessTime,createTime
} catch (IOException e) {
     System.err.println(e);
}
或者使用setLastModifiedTime
long time = System.currentTimeMillis();
FileTime fileTime = FileTime.fromMillis(time);
try {
     Files.setLastModifiedTime(path, fileTime);
} catch (IOException e) {
     System.err.println(e);
}
或者使用setAttribute
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;

try {
     Files.setAttribute(path, "basic:lastModifiedTime", fileTime, NOFOLLOW_LINKS);
     Files.setAttribute(path, "basic:creationTime", fileTime, NOFOLLOW_LINKS);
     Files.setAttribute(path, "basic:lastAccessTime", fileTime, NOFOLLOW_LINKS);
} catch (IOException e) {
     System.err.println(e);
}

try {
     FileTime lastModifiedTime = (FileTime)Files.getAttribute(path,"basic:lastModifiedTime", NOFOLLOW_LINKS);
     FileTime creationTime = (FileTime)Files.getAttribute(path,"basic:creationTime", NOFOLLOW_LINKS);
     FileTime lastAccessTime = (FileTime)Files.getAttribute(path,"basic:lastAccessTime", NOFOLLOW_LINKS);
     System.out.println("New last modified time: " + lastModifiedTime);
     System.out.println("New creation time: " + creationTime);
     System.out.println("New last access time: " + lastAccessTime);
} catch (IOException e) {
     System.err.println(e);
}
  • 2.4 Dos视图
Dos视图扩展了basic,支持Dos或者Samba文件系统。
•  isReadOnly(): Returns the readonly attribute’s value (if true, the file can’t be deleted or updated)
•  isHidden(): Returns the hidden attribute’s value (if true, the file is not visible to the users)
•  isArchive(): Returns the archive attribute’s value (specific to backup programs)
•  isSystem(): Returns the system attribute’s value (if true, the file belongs to the operating system)

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.DosFileAttributes;
...
DosFileAttributes attr = null;
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");

try {
     attr = Files.readAttributes(path, DosFileAttributes.class);
     Files.setAttribute(path, "dos:hidden", true, NOFOLLOW_LINKS);
     boolean hidden = (Boolean) Files.getAttribute(path, "dos:hidden", NOFOLLOW_LINKS);
} catch (IOException e) {
     System.err.println(e);
}

System.out.println("Is read only ? " + attr.isReadOnly());
System.out.println("Is Hidden ? " + attr.isHidden());
System.out.println("Is archive ? " + attr.isArchive());
System.out.println("Is system ? " + attr.isSystem());

Is read only ? false
Is Hidden ? false
Is archive ? true
Is system ? false

The generally accepted form is [view-name:]attribute-name. The view-name is dos.
•  hidden
•  readonly
•  system
•  archive

  • 2.5 FileOwner视图
  • 2.5.1 使用Files.setOwner设置owner
UserPrincipal owner = null;
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     owner = path.getFileSystem().getUserPrincipalLookupService(). lookupPrincipalByName("apress"); //apress为权限名
     Files.setOwner(path, owner);
} catch (IOException e) {
     System.err.println(e);
}

  • 2.5.2使用FileOwnerAttributeView.setOwner()设置owner
UserPrincipal owner = null;
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
FileOwnerAttributeView foav = Files.getFileAttributeView(path, FileOwnerAttributeView.class);
try {
     owner = path.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("apress");
     foav.setOwner(owner);
} catch (IOException e) {
     System.err.println(e);
}

  • 2.5.3 使用Files.setAttribute()设置owner
UserPrincipal owner = null;
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     owner = path.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByName("apress");
     Files.setAttribute(path, "owner:owner", owner, NOFOLLOW_LINKS);
} catch (IOException e) {
     System.err.println(e);
}

  • 2.5.4 使用FileOwnerAttributeView.getOwner()获取owner
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
FileOwnerAttributeView foav = Files.getFileAttributeView(path, FileOwnerAttributeView.class);
try {
     String owner = foav.getOwner().getName();
     System.out.println(owner);
} catch (IOException e) {
     System.err.println(e);
}

  • 2.5.5使用Files.getAttribute()获取owner
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     UserPrincipal owner = (UserPrincipal) Files.getAttribute(path, "owner:owner", NOFOLLOW_LINKS);
     System.out.println(owner.getName());
} catch (IOException e) {
     System.err.println(e);
}

The generally accepted form is [view-name:]attribute-name. The view-name is owner.只有一个owner属性。
  • 2.6 POSIX视图
PosixFileAttributes attr = null;
Path path = Paths.get("/home/rafaelnadal/tournaments/2009/BNP.txt");
try {
     attr = Files.readAttributes(path, PosixFileAttributes.class);
} catch (IOException e) {
     System.err.println(e);
}
System.out.println("File owner: " + attr.owner().getName());
System.out.println("File group: " + attr.group().getName());
System.out.println("File permissions: " + attr.permissions().toString());

try {
     attr = Files.getFileAttributeView(path, PosixFileAttributeView.class).readAttributes();
} catch (IOException e) {
     System.err.println(e);
}


The generally accepted form is [view-name:]attribute-name. The view-name is posix.
属性:
•  permissions
•  group

  • 2.6.1 POSIX Permissions
Path new_path = Paths.get("/home/rafaelnadal/tournaments/2009/new_BNP.txt");
FileAttribute<Set<PosixFilePermission>> posixattrs = PosixFilePermissions.asFileAttribute(attr.permissions());
try {
     Files.createFile(new_path, posixattrs);
} catch (IOException e) {
     System.err.println(e);
}

使用 fromString()创建PosixFilePermission对象集合。
Set<PosixFilePermission> permissions = PosixFilePermissions.fromString("rw-r--r--");
try {
     Files.setPosixFilePermissions(new_path, permissions);
} catch (IOException e) {
     System.err.println(e);
}

  • 2.6.2 POSIX Group Owner
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.GroupPrincipal;
import java.nio.file.attribute.PosixFileAttributeView;

Path path = Paths.get("/home/rafaelnadal/tournaments/2009/BNP.txt");
try {
     GroupPrincipal group = path.getFileSystem().getUserPrincipalLookupService().lookupPrincipalByGroupName("apressteam");
     Files.getFileAttributeView(path, PosixFileAttributeView.class).setGroup(group);
} catch (IOException e) {
     System.err.println(e);
}
或者
try {
     GroupPrincipal group = (GroupPrincipal) Files.getAttribute(path, "posix:group", NOFOLLOW_LINKS);
     System.out.println(group.getName());
} catch (IOException e) {
     System.err.println(e);
}

Note You can gain access to owners by calling  FileOwnerAttributeView.getOwner()and FileOwnerAttributeView.setOwner() , which are inherited in the POSIX view.
  • 2.7 ACL视图
  • 2.7.1 使用Files.getFileAttributeView()获取ACL
List<AclEntry> acllist = null;
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
AclFileAttributeView aclview = Files.getFileAttributeView(path, AclFileAttributeView.class);
try {
     acllist = aclview.getAcl();
} catch (IOException e) {
     System.err.println(e);
}
  • 2.7.2 使用Files.getAttribute()获取ACL
List<AclEntry> acllist = null;
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     acllist = (List<AclEntry>) Files.getAttribute(path, "acl:acl", NOFOLLOW_LINKS);
} catch (IOException e) {
     System.err.println(e);
}


The generally accepted form is [view-name:]attribute-name. The view-name is acl.
属性有:
•  acl
•  owner

  • 2.7.3 Read ACL Entries
每个ACLentry有4个组成部分:
•  Type: Determines if the entry grants or denies access. It can be ALARM, ALLOW, AUDIT, or DENY.
•  Principal: The identity to which the entry grants or denies access. This is mapped as a UserPrincipal.
•  Permissions: A set of permissions. Mapped as Set<AclEntryPermission>.
•  Flags: A set of flags to indicate how entries are inherited and propagated. Mapped as Set<AclEntryFlag>.

for (AclEntry aclentry : acllist) {
     System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++");
     System.out.println("Principal: " + aclentry.principal().getName());
     System.out.println("Type: " + aclentry.type().toString());
     System.out.println("Permissions: " + aclentry.permissions().toString());
     System.out.println("Flags: " + aclentry.flags().toString());
}

++++++++++++++++++++++++++++++++++++++++++++++++++++
Principal: BUILTIN\Administrators
Type: ALLOW
Permissions: [READ_ATTRIBUTES, DELETE_CHILD, WRITE_ATTRIBUTES, WRITE_ACL, WRITE_NAMED_ATTRS, WRITE_OWNER, READ_NAMED_ATTRS, DELETE, READ_DATA, EXECUTE, SYNCHRONIZE, READ_ACL, APPEND_DATA, WRITE_DATA]
Flags: []
++++++++++++++++++++++++++++++++++++++++++++++++++++
Principal: NT AUTHORITY\SYSTEM
Type: ALLOW
Permissions: [READ_ATTRIBUTES, DELETE_CHILD, WRITE_ATTRIBUTES, WRITE_ACL, WRITE_NAMED_ATTRS, WRITE_OWNER, READ_NAMED_ATTRS, DELETE, READ_DATA, EXECUTE, SYNCHRONIZE, READ_ACL, APPEND_DATA, WRITE_DATA]
Flags: []
++++++++++++++++++++++++++++++++++++++++++++++++++++
Principal: BUILTIN\Users
Type: ALLOW
Permissions: [READ_ATTRIBUTES, READ_DATA, EXECUTE, SYNCHRONIZE, READ_ACL, READ_NAMED_ATTRS]
Flags: []
++++++++++++++++++++++++++++++++++++++++++++++++++++
Principal: NT AUTHORITY\Authenticated Users
Type: ALLOW
Permissions: [READ_ATTRIBUTES, READ_DATA, EXECUTE, SYNCHRONIZE, READ_ACL, APPEND_DATA, WRITE_DATA, WRITE_ATTRIBUTES, WRITE_NAMED_ATTRS, READ_NAMED_ATTRS, DELETE]
Flags: []

  • 2.7.4为acl赋予新的访问
If you want to grant a new access to a principal, then you must follow this process:
1.  Look up the principal by calling the FileSystem.getUserPrincipalLookupService() method.
2.  Get the ACL view (as previously described).
3.  Create a new entry by using the AclEntry.Builder object.
4.  Read the ACL (as previous described).
5.  Insert the new entry (recommended before any DENY entry).
6.  Rewrite the ACL by using setAcl() or setAttribute().

try {
     //Lookup for the principal
     UserPrincipal user = path.getFileSystem().getUserPrincipalLookupService();

     //Get the ACL view
     AclFileAttributeView view = Files.getFileAttributeView(path,  AclFileAttributeView.class);

     //Create a new entry
     AclEntry entry = AclEntry.newBuilder().setType(AclEntryType.ALLOW).
setPrincipal(user).setPermissions(AclEntryPermission.READ_DATA,                           AclEntryPermission.APPEND_DATA).build();

     //read ACL
     List<AclEntry> acl = view.getAcl();

     //Insert the new entry
     acl.add(0, entry);

     //rewrite ACL
     view.setAcl(acl);

     //or, like this
     //Files.setAttribute(path, "acl:acl", acl, NOFOLLOW_LINKS);
} catch (IOException e) {
     System.err.println(e);
}

 Note You can gain access to owners by calling  FileOwnerAttributeView.getOwner()and FileOwnerAttributeView.setOwner() , which are inherited in the ACL view.
  • 2.8 File Store属性
  • 2.8.1获取所有的File Store属性
FileSystem fs = FileSystems.getDefault();
for (FileStore store : fs.getFileStores()) {
     try {
          long total_space = store.getTotalSpace() / 1024;
          long used_space = (store.getTotalSpace() - store.getUnallocatedSpace()) / 1024;
          long available_space = store.getUsableSpace() / 1024;
          boolean is_read_only = store.isReadOnly();
          System.out.println("--- " + store.name() + " --- " + store.type());
          System.out.println("Total space: " + total_space);
          System.out.println("Used space: " + used_space);
          System.out.println("Available space: " + available_space);
          System.out.println("Is read only? " + is_read_only);
     } catch (IOException e) {
          System.err.println(e);
     }
}

--- OS --- NTFS
Total space: 81919996
Used space: 58143972
Available space: 23776024
Is read only? false
--- Data --- NTFS
Total space: 388543484
Used space: 112091812
Available space: 276451672
Is read only? false
--- Lenovo_Recovery --- NTFS
Total space: 16383996
Used space: 11397128
Available space: 4986868
Is read only? false
  • 2.8.2 获取文件所在的File Store的属性
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     FileStore store = Files.getFileStore(path);
     long total_space = store.getTotalSpace() / 1024;
     long used_space = (store.getTotalSpace() - store.getUnallocatedSpace()) / 1024;
     long available_space = store.getUsableSpace() / 1024;
     boolean is_read_only = store.isReadOnly();

     System.out.println("--- " + store.name() + " --- " + store.type());
     System.out.println("Total space: " + total_space);
     System.out.println("Used space: " + used_space);
     System.out.println("Available space: " + available_space);
     System.out.println("Is read only? " + is_read_only);
} catch (IOException e) {
     System.err.println(e);
}

或者
FileStoreAttributeView fsav = store.getFileStoreAttributeView(FileStoreAttributeView.class);
  • 2.9 用户自定义的文件属性
  • 2.9.1 是否支持用户自定义属性
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
try {
     FileStore store = Files.getFileStore(path);
     if (!store.supportsFileAttributeView(UserDefinedFileAttributeView.class)) {
          System.out.println("The user defined attributes are not supported on: " + store);
     } else {
          System.out.println("The user defined attributes are supported on: " + store);
     }
} catch (IOException e) {
     System.err.println(e);
}
  • 2.9.2用户自定义属性的操作
定义用户自定义属性:
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
try {
     int written = udfav.write("file.description", Charset.defaultCharset().encode("This file contains private information!"));
} catch (IOException e) {
     System.err.println(e);
}

 Note In addition, you can write an attribute using the  setAttribute() method. You can write it from a buffer or byte array ( byte[] ).

显示用户自定义属性的名称和值大小:
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
try {
     for (String name : udfav.list()) {
          System.out.println(udfav.size(name) + " " + name);
     }
} catch (IOException e) {
     System.err.println(e);
}

获取用户自定义属性的值:
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
try {
     int size = udfav.size("file.description");
     ByteBuffer bb = ByteBuffer.allocateDirect(size);
     udfav.read("file.description", bb);
     bb.flip();
     System.out.println(Charset.defaultCharset().decode(bb).toString());
} catch (IOException e) {
     System.err.println(e);
}
Note You can also read an attribute by using the  getAttribute() method. The value is returned as byte array ( byte[] ).

删除用户自定义属性:
Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");
UserDefinedFileAttributeView udfav = Files.getFileAttributeView(path, UserDefinedFileAttributeView.class);
try {
     udfav.delete("file.description");
} catch (IOException e) {
     System.err.println(e);
}
  • 3 管理软链接和硬链接
  • 3.1 链接简介
When a file has two names of equal weight and the inode table (Linux files don’t actually live in directories; they are assigned an inode number, which Linux uses to locate them) points directly to the blocks on the disk that contain the data, the link is a hard link.
Think of a hard link as a directory reference or pointer to a file. When a file has one main name and an extra entry in the file name table that refers any accesses back to the main name, the link is a symbolic link. 

软硬链接的区别:
•硬链接只能针对文件,不能对目录,而软链接可以针对文件和目录。 
•硬链接不能跨文件系统,软链接可以。 
•硬链接的目标必须先存在,软可以可以不存在。 
•删除硬链接指向的原文件,不会删除硬链接本身,并且硬链接仍然可以访问原文件内容。
删除软链接指向的原文件,不会删除软链接本身,但没有原文件,软链接就没有意义了。 
•删除 硬链接或者软链接本身,原文件仍然存在。 
•硬链接的inode节点现象和原文件是一样的。软链接没有这个限制。 
•硬两件和普通文件类似,所以很难区别是硬链接还是普通文件。软链接的目标可以不存在,因此它非常灵活。 

  • 3.2通过命令行创建链接
Windows平台:
/D Creates a directory symbolic link. Default is a file symbolic link.
/H Creates a hard link instead of a symbolic link.
/J Creates a Directory Junction.
Link specifies the new symbolic link name.
Target specifies the path (relative or absolute) that the new link refers to.

mklink /D C:\rafaelnadal C:\rafaelnadal\photos

ln –s /home/rafaelnadal/photos /home/rafaelnadal
rm /home/rafaelnadal

  • 3.3创建软链接
Path link = FileSystems.getDefault().getPath("rafael.nadal.1");
Path target= FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_winner.jpg");
try {
     Files. createSymbolicLink(link, target);
} catch (IOException | UnsupportedOperationException | SecurityException e) {
     if (e instanceof SecurityException) {
          System.err.println("Permission denied!");
     }
     if (e instanceof UnsupportedOperationException) {
          System.err.println("An unsupported operation was detected!");
     }
     if (e instanceof IOException) {
          System.err.println("An I/O error occurred!");
     }

     System.err.println(e);
}
或者
Path link = FileSystems.getDefault().getPath("rafael.nadal.2");
Path target = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_winner.jpg");
try {
     PosixFileAttributes attrs = Files.readAttributes(target, PosixFileAttributes.class);
     FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(attrs.permissions());

     Files.createSymbolicLink(link, target,  attr);
} catch (IOException | UnsupportedOperationException | SecurityException e) {
     if (e instanceof SecurityException) {
          System.err.println("Permission denied!");
     }
     if (e instanceof UnsupportedOperationException) {
          System.err.println("An unsupported operation was detected!");
     }
     if (e instanceof IOException) {
          System.err.println("An I/O error occured!");
     }
     System.err.println(e);
}

或者
Path link = FileSystems.getDefault().getPath("rafael.nadal.3");
Path target = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_winner.jpg");

try {

     Files.createSymbolicLink(link, target);
     FileTime lm = (FileTime) Files.getAttribute(target,"basic:lastModifiedTime", NOFOLLOW_LINKS);
     FileTime la = (FileTime) Files.getAttribute(target,"basic:lastAccessTime", NOFOLLOW_LINKS);
     Files.setAttribute(link, "basic:lastModifiedTime", lm, NOFOLLOW_LINKS);
     Files.setAttribute(link, "basic:lastAccessTime", la, NOFOLLOW_LINKS);

} catch (IOException | UnsupportedOperationException | SecurityException e) {

     if (e instanceof SecurityException) {
          System.err.println("Permision denied!");
     }

     if (e instanceof UnsupportedOperationException) {
          System.err.println("An unsupported operation was detected!");
     }

     if (e instanceof IOException) {
          System.err.println("An I/O error occured!");
     }

     System.err.println(e);
}

  • 3.4 创建硬链接
public class Main {
     public static void main(String[] args) {
     Path link = FileSystems.getDefault().getPath("rafael.nadal.4");
     Path target = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_winner.jpg");
     try {
          Files. createLink(link, target);
          System.out.println("The link was successfully created!");
     } catch (IOException | UnsupportedOperationException | SecurityException e) {
          if (e instanceof SecurityException) {
               System.err.println("Permission denied!");
          }
          if (e instanceof UnsupportedOperationException) {
               System.err.println("An unsupported operation was detected!");
          }
          if (e instanceof IOException) {
               System.err.println("An I/O error occured!");
          }
          System.err.println(e);
          }
     }
}
  • 3.5 检查软链接
Path link = FileSystems.getDefault().getPath("rafael.nadal.5");
Path target = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_winner.jpg");
try {
     Files.createSymbolicLink(link, target);
  …
}

//check if a path is a symbolic link - solution 1
boolean link_isSymbolicLink_1 = Files.isSymbolicLink(link);
boolean target_isSymbolicLink_1 = Files.isSymbolicLink(target);

System.out.println(link.toString() + " is a symbolic link ? " + link_isSymbolicLink_1);
System.out.println(target.toString() + " is a symbolic link ? " + target_isSymbolicLink_1);
输出:
rafael.nadal.5 is a symbolic link ? true
C:\rafaelnadal\photos\rafa_winner.jpg is a symbolic link ? false

或者通过属性
try {
     boolean link_isSymbolicLink_2 = (boolean) Files.getAttribute(link,"basic:isSymbolicLink");
     boolean target_isSymbolicLink_2 = (boolean) Files.getAttribute(target,"basic:isSymbolicLink");

     System.out.println(link.toString() + " is a symbolic link ? " + link_isSymbolicLink_2);
     System.out.println(target.toString() + " is a symbolic link ? "+ target_isSymbolicLink_2);
} catch (IOException | UnsupportedOperationException e) {
     System.err.println(e);
}
输出:
rafael.nadal.5 is a symbolic link ? true
C:\rafaelnadal\photos\rafa_winner.jpg is a symbolic link ? false

  • 3.6定位链接目标
Path link = FileSystems.getDefault().getPath("rafael.nadal.6");
Path target = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_winner.jpg");…

try {
     Path linkedpath = Files.readSymbolicLink(link);
     System.out.println(linkedpath.toString());
} catch (IOException e) {
     System.err.println(e);
}

  • 3.7检测链接和文件是否相同
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;

public class CheckSymbolicLink {
    public static void main(String[] args) {


        Path link = FileSystems.getDefault().getPath("test.link");
        Path target = FileSystems.getDefault().getPath("C:/test.ini");
        try{
            Files.createSymbolicLink(link, target);
        } catch (IOException | UnsupportedOperationException |
                SecurityException e) {
            e.printStackTrace();
        }

        try {
            boolean isSame = Files.isSameFile(link, target);
            if (isSame) {
                System.out.println(link + " And " + target + " are the same location.");
            }
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}
输出:
test.link And C:\test.ini are the same location.

  • 4 文件和目录
  • 4.1 文件和目录的检测方法
  • 4.1.1 检测文件或目录是否存在
Path path = FileSystems.getDefault().getPath("C:/rafaelnadal/tournaments/2009","AEGON.txt");

boolean path_exists = Files.exists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS});
boolean path_notexists = Files.notExists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS});

NOTE: !Files.exists(…) is not equivalent to  Files.notExists(…) and the  notExists() method is not a complement of the  exists() method.因为可能还存在没有权限访问时的UNKNOWN状态。
  • 4.1.2 文件访问性
Path path = FileSystems.getDefault().getPath("C:/rafaelnadal/tournaments/2009","AEGON.txt");
boolean is_readable = Files. isReadable(path);
boolean is_writable = Files. isWritable(path);
boolean is_executable = Files. isExecutable(path);
boolean is_regular = Files. isRegularFile(path, LinkOption.NOFOLLOW_LINKS);

if ((is_readable) && (is_writable) && (is_executable) && (is_regular)) {
     System.out.println("The checked file is accessible!");
} else {
     System.out.println("The checked file is not accessible!");
}
或者
boolean is_accessible = Files.isRegularFile(path) & Files.isReadable(path) & Files.isExecutable(path) & Files.isWritable(path);
if (is_accessible) {
     System.out.println("The checked file is accessible!");
} else {
     System.out.println("The checked file is not accessible!");
}
注意:Even if these methods confirm the accessibility, there is no guarantee that the file can be accessed. The explanation resides in a well-known software bug, named time-of-check-to-time-of-use (TOCTTOU, pronounced “TOCK too”), which means that in the time between checking and using the checking result, the system may suffer different kinds of changes. Unix fans are probably familiar with this concept, but it is applicable  to any other system as well.意思就是检查通过之后又可能还是不能访问,中间存在状态改变的可能性。

  • 4.1.3 检查两个Path是否指向同一文件
Path path_1 = FileSystems.getDefault().getPath("C:/rafaelnadal/tournaments/2009", "MutuaMadridOpen.txt"); Path path_2 = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/2009",  "MutuaMadridOpen.txt");
Path path_3 = FileSystems.getDefault().getPath("/rafaelnadal/tournaments/dummy/../2009", "MutuaMadridOpen.txt");
 try {
            boolean is_same_file_12 = Files.isSameFile(path_1, path_2);
            boolean is_same_file_13 = Files.isSameFile(path_1, path_3);
            boolean is_same_file_23 = Files.isSameFile(path_2, path_3);
            System.out.println("is same file 1&2 ? " + is_same_file_12);
            System.out.println("is same file 1&3 ? " + is_same_file_13);
            System.out.println("is same file 2&3 ? " + is_same_file_23);
  } catch (IOException e) {
            System.err.println(e);
  }

  • 4.1.4 文件可见性
Path path = FileSystems.getDefault().getPath("C:/rafaelnadal/tournaments/2009","MutuaMadridOpen.txt");
try {
     boolean is_hidden = Files.isHidden(path);
     System.out.println("Is hidden ? " + is_hidden);
} catch (IOException e) {
     System.err.println(e);
}
  • 4.2 创建读目录
  • 4.2.1 列出文件系统的Root目录
Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories();
for (Path name : dirs) {
     System.out.println(name);
}

C:\
D:\
Q:\

JDK6:
File[] roots = File.listRoots();
for (File root : roots) {
     System.out.println(root);
}
  • 4.2.2创建新的目录
Path newdir = FileSystems.getDefault().getPath("C:/rafaelnadal/tournaments/2010/");
try {
     Files.createDirectory(newdir);  //如果目录已经存在,会抛出异常。
} catch (IOException e) {
     System.err.println(e);
}
或者创建是设置权限属性:
Path newdir = FileSystems.getDefault().getPath("/home/rafaelnadal/tournaments/2010/");
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rwxr-x---");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);
try {
     Files.createDirectory(newdir, attr);
} catch (IOException e) {
     System.err.println(e);
}

创建多级目录:
Path newdir= FileSystems.getDefault().getPath("C:/temp", "statistics/win/prizes");
try {
     Files.createDirectories(newdir);
} catch (IOException e) {
     System.err.println(e);
}
  • 4.2.3 列出目录内容
  Path path = Paths.get("C:/temp");

 System.out.println("\nNo filter applied:");
  try (DirectoryStream<Path> ds = Files.newDirectoryStream(path)) {
            for (Path file : ds) {
                System.out.println(file.getFileName());
            }
 } catch (IOException e) {
            System.err.println(e);
  }

  • 4.2.4 返回匹配指定模式的文件名或目录glob
•  *: Represent (match) any number of characters, including none.
•  **: Similar to *, but cross directories’ boundaries.
•  ?: Represent (match) exactly one character.
•  {}: Represent a collection of subpatterns separated by commas. For example,{A,B,C} matches A, B, or C.
•  []: Convey a set of single characters or a range of characters if the hyphen character is present. Some common examples include the following:
•  [0-9]: Matches any digit
•  [A-Z]: Matches any uppercase letter
•  [a-z,A-Z]: Matches any uppercase or lowercase letter
•  [12345]: Matches any of 1, 2, 3, 4, or 5
•  Within the square brackets, *, ?, and \ match themselves.
•  All other characters match themselves.
•  To match *, ?, or the other special characters, you can escape them by using the backslash character, \. For example, \\ matches a single backslash, and \? matches the question mark.

Path path = Paths.get("C:/rafaelnadal/tournaments/2009");

//glob pattern applied
System.out.println("\nGlob pattern applied:");
try (DirectoryStream<Path> ds = Files.newDirectoryStream(path, "*.{png,jpg,bmp}")) {
     for (Path file : ds) {
          System.out.println(file.getFileName());
     }
} catch (IOException e) {
     System.err.println(e);
}
  • 4.2.5列出基于用户自定义过滤器的目录内容
实现DirectoryStream.Filter<T>接口。
Path path = Paths.get("C:/rafaelnadal/tournaments/2009");

//user-defined filter - only directories are accepted
DirectoryStream.Filter<Path> dir_filter = new DirectoryStream.Filter<Path>() {
     public boolean accept(Path path) throws IOException {
          return (Files.isDirectory(path, NOFOLLOW_LINKS));
     }
};

try (DirectoryStream<Path> ds = Files.newDirectoryStream(path, dir_filter)) {
     for (Path file : ds) {
          System.out.println(file.getFileName());
     }
} catch (IOException e) {
     System.err.println(e);
}

DirectoryStream.Filter<Path> size_filter = new DirectoryStream.Filter<Path>() {
     public boolean accept(Path path) throws IOException {
          return (Files.size(path) > 204800L);
     }
};

DirectoryStream.Filter<Path> time_filter = new DirectoryStream.Filter<Path>() {
     public boolean accept(Path path) throws IOException {
          long currentTime = FileTime.fromMillis(System.currentTimeMillis()).to(TimeUnit.DAYS);
          long modifiedTime = ((FileTime) Files.getAttribute(path, "basic:lastModifiedTime", NOFOLLOW_LINKS)).to(TimeUnit.DAYS);
          if (currentTime == modifiedTime) {
               return true;
          }
          return false;
          }
};


DirectoryStream.Filter<Path> hidden_filter = new DirectoryStream.Filter<Path>() {
     public boolean accept(Path path) throws IOException {
          return (Files.isHidden(path));
     }
};
  • 4.3 创建读写文件
  • 4.3.1 标准的Open选项
READ 以read访问方式打开文件 
WRITE  以write访问方式打开文件 
CREATE创建一个不存在的文件
CREATE_NEW  创建一个文件,如果已经存在,则抛出异常
APPPEND  在文件末尾追加数据
DELETE_ON_CLOSE  到达文件流末尾时,删除文件,一般用于临时文件 
TRUNCATE_EXISTING   截断文件
SPARSE  Causes the newly created file to be sparse
SYNC  Keeps the file content and metadata synchronized with the underlying storage device
DSYNC  Keeps the file content synchronized with the underlying storage device
  • 4.3.2 创建文件
Path newfile = FileSystems.getDefault().getPath("C:/rafaelnadal/tournaments/2010/SonyEricssonOpen.txt");

try {
     Files.createFile(newfile);
} catch (IOException e) {
     System.err.println(e);
}


Path newfile = FileSystems.getDefault().getPath("/home/rafaelnadal/tournaments/2010/SonyEricssonOpen.txt");
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);
try {
     Files.createFile(newfile, attr);
} catch (IOException e) {
     System.err.println(e);
}
  • 4.3.3写小文件
(1)
Path ball_path = Paths.get("C:/rafaelnadal/photos", "ball.png");
byte[] ball_bytes = new byte[]{(byte)0x89,(byte)0x50,(byte)0x4e,(byte)0x47,(byte)0x0d,(byte)0x0a,(byte)0x1a,(byte)0x0a,
     (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x0d,(byte)0x49,(byte)0x48,(byte)0x44,(byte)0x52,
     (byte)0x00,(byte)0x00,(byte)0x00,(byte)0x10,(byte)0x00,(byte)0x00,(byte)0x00,(byte)0x10,
     (byte)0x08,(byte)0x02,(byte)0x00,(byte)0x49,(byte)0x45,(byte)0x4e,(byte)0x44,(byte)0xae,(byte)0x42,(byte)0x60,(byte)0x82
};
try {
     Files.write(ball_path, ball_bytes);
} catch (IOException e) {
     System.err.println(e);
}

(2)
Path rf_wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");
String rf_wiki = "Rafael \"Rafa\" Nadal Parera (born 3 June 1986) is a Spanish professional  tennis "
                + "player and a former World No. 1. As of 29 August 2011 (2011 -08-29)[update], he is ranked No. 2 "
                + "by the Association of Tennis Professionals (ATP). He is widely regarded a one of the greatest players  "
                + "of all time; his success on clay has earned him the nickname The King of Clay\", and has prompted "
                 + "many experts to regard him as the greatest clay court player of all time. Some of his best wins are:";

try {
     byte[] rf_wiki_byte = rf_wiki.getBytes("UTF-8");
     Files.write(rf_wiki_path, rf_wiki_byte);
} catch (IOException e) {
     System.err.println(e);
}

(3)
Path rf_wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");

Charset charset = Charset.forName("UTF-8");
ArrayList<String> lines = new ArrayList<>();
lines.add("\n");
lines.add("Rome Masters - 5 titles in 6 years");
lines.add("Monte Carlo Masters - 7 consecutive titles (2005-2011)");
lines.add("Australian Open - Winner 2009");
lines.add("Roland Garros - Winner 2005-2008, 2010, 2011");
lines.add("Wimbledon - Winner 2008, 2010");
lines.add("US Open - Winner 2010");
try {
     Files.write(rf_wiki_path, lines, charset, StandardOpenOption.APPEND);
} catch (IOException e) {
     System.err.println(e);
}
  • 4.3.4 读小文件
Path ball_path = Paths.get("C:/rafaelnadal/photos", "ball.png");

try {
     byte[] ballArray = Files.readAllBytes(ball_path);
} catch (IOException e) {
     System.out.println(e);
}

Files.write(ball_path.resolveSibling("bytes_to_ball.png"), ballArray);


BufferedImage bufferedImage = ImageIO.read(new ByteArrayInputStream(ballArray));
ImageIO.write(bufferedImage, "png", (ball_path.resolveSibling("bytes_to_ball.png")).toFile());

(1)
Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");

try {
     byte[] wikiArray = Files.readAllBytes(wiki_path);
     String wikiString = new String(wikiArray, "ISO-8859-1");
     System.out.println(wikiString);
} catch (IOException e) {
     System.out.println(e);
}

(2)
Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");

Charset charset = Charset.forName("ISO-8859-1");
try {
     List<String> lines = Files.readAllLines(wiki_path, charset);
     for (String line : lines) {
          System.out.println(line);
     }
} catch (IOException e) {
     System.out.println(e);
}
readAllLines方法以下面的字符表示行结束。
•  \u000D followed by \u000A: CARRIAGE RETURN followed by LINE FEED
•  \u000A: LINE FEED
•  \u000D: CARRIAGE RETURN
  • 4.3.5使用Buffered Streams
Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");

Charset charset = Charset.forName("UTF-8");
String text = "\nVamos Rafa!";
try (BufferedWriter writer = Files.newBufferedWriter(wiki_path, charset,  StandardOpenOption.APPEND)) {
     writer.write(text);
} catch (IOException e) {
     System.err.println(e);
}

Path wiki_path = Paths.get("C:/rafaelnadal/wiki", "wiki.txt");

Charset charset = Charset.forName("UTF-8");
try (BufferedReader reader = Files.newBufferedReader(wiki_path, charset)) {
     String line = null;
     while ((line = reader.readLine()) != null) {
          System.out.println(line);
     }
} catch (IOException e) {
     System.err.println(e);
}

非缓存的OutputStream
Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");
String racquet = "Racquet: Babolat AeroPro Drive GT";
byte data[] = racquet.getBytes();
try (OutputStream outputStream = Files.newOutputStream(rn_racquet)) {
          outputStream.write(data);
} catch (IOException e) {
     System.err.println(e);
}
转换为Buffer Stream
Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");
String string = "\nString: Babolat RPM Blast 16";
try (OutputStream outputStream = Files.newOutputStream(rn_racquet, StandardOpenOption.APPEND);
           BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) {
     writer.write(string);
} catch (IOException e) {
     System.err.println(e);
}

非缓存的InputStream
Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");

int n;
try (InputStream in = Files.newInputStream(rn_racquet)) {
     while ((n = in.read()) != -1) {
          System.out.print((char)n);
     }
} catch (IOException e) {
     System.err.println(e);
}
使用缓存数组:
Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");

int n;
byte[] in_buffer = new byte[1024];
try (InputStream in = Files.newInputStream(rn_racquet)) {
     while ((n = in.read(in_buffer)) != -1) {
          System.out.println(new String(in_buffer));
     }
} catch (IOException e) {
     System.err.println(e);
}

使用BufferedReader
Path rn_racquet = Paths.get("C:/rafaelnadal/equipment", "racquet.txt");

try (InputStream in = Files.newInputStream(rn_racquet);
BufferedReader reader = new BufferedReader(new InputStreamReader(in))) {
     String line = null;
     while ((line = reader.readLine()) != null) {
          System.out.println(line);
     }
} catch (IOException e) {
     System.err.println(e);
}
  • 4.4 创建临时目录和文件
  • 4.4.1 创建临时目录
Windows平台的临时目录为TEMP环境变量,一般为C:\Temp, %Windows%\Temp, 或者每个用户的临时目录 Local Settings\Temp;Linux/Unix的临时目录为/tmp或者/var/tmp.
使用下面的代码获取临时目录:
String default_tmp = System.getProperty("java.io.tmpdir");
System.out.println(default_tmp);

String tmp_dir_prefix = "nio_";
try {
     //passing null prefix
     Path tmp_1 = Files.createTempDirectory(null);
     System.out.println("TMP: " + tmp_1.toString());

     //set a prefix
     Path tmp_2 = Files.createTempDirectory(tmp_dir_prefix);
     System.out.println("TMP: " + tmp_2.toString());

} catch (IOException e) {
     System.err.println(e);
}
指定临时目录:
Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp/");
String tmp_dir_prefix = "rafa_";

try {
     //create a tmp directory in the base dir
     Path tmp = Files. createTempDirectory(basedir, tmp_dir_prefix);
     System.out.println("TMP: " + tmp.toString());
} catch (IOException e) {
     System.err.println(e);
}
  • 4.4.1.1使用Shutdown-Hook删除临时目录

Runtime.getRuntime().addShutdownHook(new Thread() {
     @Override
     public void run() {
          System.out.println("Shutdown-hook activated ...");
          //… here, cleanup/save resources
          System.out.println("Shutdown-hook successfully executed ...");
     }
});

递归删除临时目录,可以参考第5章Walks。
final Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp/");
final String tmp_dir_prefix = "rafa_";
try {
     //create a tmp directory in the base dir
     final Path tmp_dir = Files.createTempDirectory(basedir, tmp_dir_prefix);

     Runtime.getRuntime().addShutdownHook(new Thread() {
          @Override
          public void run() {
               System.out.println("Deleting the temporary folder ...");
               try (DirectoryStream<Path> ds = Files.newDirectoryStream(tmp_dir)) {
                    for (Path file : ds) {
                         Files.delete(file);
                    }
                    Files.delete(tmp_dir);
               } catch (IOException e) {
               System.err.println(e);
          }
          System.out.println("Shutdown-hook completed...");
     }
});
//simulate some I/O operations over the temporary file by sleeping 10 seconds
//when the time expires, the temporary file is deleted
Thread.sleep(10000);
//operations done
} catch (IOException | InterruptedException e) {
     System.err.println(e);
}

  • 4.4.1.2 使用deleteOnExit()删除目录
Because this method must be called for each temporary file or directory, it is considered the least attractive choice because it will consume memory for each temporary entity.

NOTE: If your system is active for a long period of time or creates many temporary files or directories  in a short period of time, then using  deleteOnExit() is a bad idea! Before you choose to use  deleteOnExit() ,consider that it can use a lot of memory that will not be released until the JVM terminates.

Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp/");
String tmp_dir_prefix = "rafa_";
try {
     //create a tmp directory in the base dir
     Path tmp_dir = Files.createTempDirectory(basedir, tmp_dir_prefix);
     File asFile = tmp_dir.toFile();
     asFile.deleteOnExit();

     //simulate some I/O operations over the temporary file by sleeping 10 seconds
     //when the time expires, the temporary file is deleted
     //EACH CREATED TEMPORARY ENTRY SHOULD BE REGISTERED FOR DELETE ON EXIT
     Thread.sleep(10000);
//operations done
} catch (IOException | InterruptedException e) {
     System.err.println(e);
}

  • 4.4.2 创建临时文件
//output: C:\Users\Leo\AppData\Local\Temp\
String default_tmp = System.getProperty("java.io.tmpdir");


String tmp_file_prefix = "rafa_";
String tmp_file_sufix=".txt";
try {
     //passing null prefix/suffix
     Path tmp_1 = Files.createTempFile(null,null);
     System.out.println("TMP: " + tmp_1.toString());

     //set a prefix and a suffix
     Path tmp_2 = Files.createTempFile(tmp_file_prefix, tmp_file_sufix);
     System.out.println("TMP: " + tmp_2.toString());
} catch (IOException e) {
     System.err.println(e);
}

指定临时文件所在的目录:
Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp");
String tmp_file_prefix = "rafa_";
String tmp_file_sufix=".txt";
try {
     Path tmp_3 = Files.createTempFile(basedir, tmp_file_prefix, tmp_file_sufix);
     System.out.println("TMP: " + tmp_3.toString());
} catch (IOException e) {
     System.err.println(e);
}

  • 4.4.2.1 基于Shutdown-hook删除临时文件
Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp");
String tmp_file_prefix = "rafa_";
String tmp_file_sufix = ".txt";

try {
     final Path tmp_file = Files.createTempFile(basedir, tmp_file_prefix, tmp_file_sufix);
     Runtime.getRuntime().addShutdownHook(new Thread() {
          @Override
          public void run() {
               System.out.println("Deleting the temporary file ...");
               try {
                    Files.delete(tmp_file);
               } catch (IOException e) {
               System.err.println(e);
            }
     System.out.println("Shutdown hook completed...");
     }
});

//simulate some I/O operations over the temporary file by sleeping 10 seconds
//when the time expires, the temporary file is deleted
     Thread.sleep(10000);
     //operations done
} catch (IOException | InterruptedException e) {
     System.err.println(e);
}
  • 4.4.2.2使用deleteOnExit()删除临时文件
Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp");
String tmp_file_prefix = "rafa_";
String tmp_file_sufix = ".txt";
try {
     final Path tmp_file = Files.createTempFile(basedir, tmp_file_prefix, tmp_file_sufix);
     File asFile = tmp_file.toFile();
     asFile.deleteOnExit();
     //simulate some I/O operations over the temporary file by sleeping 10 seconds

     //when the time expires, the temporary file is deleted
     Thread.sleep(10000);
     //operations done
} catch (IOException | InterruptedException e) {
     System.err.println(e);
}
  • 4.4.2.3 使用DELETE_ON_CLOSE删除临时文件
Path basedir = FileSystems.getDefault().getPath("C:/rafaelnadal/tmp");
String tmp_file_prefix = "rafa_";
String tmp_file_sufix = ".txt";
Path tmp_file = null;
try {
     tmp_file = Files.createTempFile(basedir, tmp_file_prefix, tmp_file_sufix);
} catch (IOException e) {
     System.err.println(e);
}
try (OutputStream outputStream = Files.newOutputStream(tmp_file, StandardOpenOption.DELETE_ON_CLOSE);
          BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) {

     //simulate some I/O operations over the temporary file by sleeping 10 seconds
     //when the time expires, the temporary file is deleted
     Thread.sleep(10000);
     //operations done
} catch (IOException | InterruptedException e) {
     System.err.println(e);
}

流关闭时会删除文件。

  • 4.4.3 删除、移动、复制目录和文件
  • 4.4.3.1 删除文件和目录
Path path = FileSystems.getDefault().getPath("C:/rafaelnadal/photos", "rafa_1.jpg");
//delete the file
try {
     Files.delete(path);
} catch (NoSuchFileException | DirectoryNotEmptyException | IOException | SecurityException e) {
     System.err.println(e);
}
deleteIfExists在多线程场景下比较有用:
try {
     boolean success = Files.deleteIfExists(path);
     System.out.println("Delete status: " + success);
} catch (DirectoryNotEmptyException | IOException | SecurityException e) {
     System.err.println(e);
}

如果删除目录,则必须是空目录,否则递归删除晴参考第5章。如果删除的是符号链接,则仅指符号链接本身,而不是其目标。

  • 4.4.3.2 复制文件和目录
•   REPLACE_EXISTING: If the copied file already exists, then it is replaced (in the case of a nonempty directory, a FileAlreadyExistsException is thrown). When dealing  with a symbolic link, the target of the link it is not copied; only the link is copied.
•   COPY_ATTRIBUTES: Copy a file with its associated attributes (at least, the  lastModifiedTime attribute is supported and copied).
•   NOFOLLOW_LINKS: Symbolic links should not be followed.

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS; 

Note 符合链接的复制.By default, when copying a symbolic link, the target of that link is copied. Copying only the link itself can be accomplished through the  REPLACE_EXISTING and  NOFOLLOW_LINKS options. Moreover, file attributes are not required to be copied.

Caution  Trying to copy a nonempty directory will result in an empty directory. This is a task usually implemented as a recursive operation, as you will see in Chapter 5. Moreover, copying a file is not an atomic operation, which means that an  IOException exception can be thrown and the copy aborted even if the target file is incomplete or the attributes were not totally copied. 

(1)两个Path直接复制
Path copy_from = Paths.get("C:/rafaelnadal/grandslam/AustralianOpen", "draw_template.txt");
Path copy_to= Paths.get("C:/rafaelnadal/grandslam/USOpen",copy_from.getFileName().toString());
try {
      Files.copy(copy_from, copy_to, REPLACE_EXISTING, COPY_ATTRIBUTES, NOFOLLOW_LINKS);
} catch (IOException e) {
     System.err.println(e);
}

(2)从Input Stream复制到文件
Path copy_from = Paths.get("C:/rafaelnadal/grandslam/AustralianOpen", "draw_template.txt");
Path copy_to = Paths.get("C:/rafaelnadal/grandslam/Wimbledon", "draw_template.txt");
try (InputStream is = new FileInputStream(copy_from.toFile())) {
      Files.copy(is, copy_to, REPLACE_EXISTING);
} catch (IOException e) {
     System.err.println(e);
}

Path copy_to = Paths.get("C:/rafaelnadal/photos/rafa_winner_2.jpg");
URI u = URI.create("https://lh6.googleusercontent.com/udGIidomAM/Tl8KTbYd34I/AAAAAAAAAZw/j2nH24PaZyM/s800/rafa_winner.jpg");

try (InputStream in =  u.toURL().openStream()) {
     Files.copy(in, copy_to);
} catch (IOException e) {
     System.err.println(e);
}

(3)从文件复制到Output Stream
Path copy_from = Paths.get("C:/rafaelnadal/grandslam/AustralianOpen", "draw_template.txt");
Path copy_to = Paths.get("C:/rafaelnadal/grandslam/RolandGarros", "draw_template.txt");

try (OutputStream os = new FileOutputStream(copy_to.toFile())) {
     Files.copy(copy_from, os);
} catch (IOException e) {
     System.err.println(e);
}
  • 4.4.3.3 移动文件和目录
•   REPLACE_EXISTING: If the target file already exists, then the move is still performed and the target is replaced. When dealing with a symbolic link, the symbolic link is  replaced but what it points to is not affected.
•   ATOMIC_MOVE: The file move will be performed as an atomic operation, which guarantees that any process that monitors the file’s directory will access a complete file.

import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;

By default (when no options are explicitly specified), the move() method tries to move the file to the target file, failing if the target file exists (FileAlreadyExistsException is thrown) except if the source and target are the same file (the isSameFile() method returns true), in which case this method has no effect.
  Note By default, when moving a symbolic link, the symbolic link itself is moved, not the target of that link.

  Caution  The  move() method can also be used to move empty directories. Trying to move a nonempty directory is a task usually implemented as a recursive copy operation, as you will see in Chapter 5. Nevertheless, it is possible to move a directory that it is not empty if it does not require moving the entries in the directory. In some cases a directory has entries for special files (such as links) that are created when the directory is created, and if  the directory contains only those entries, it is considered empty.

Path movefrom = FileSystems.getDefault().getPath("C:/rafaelnadal/rafa_2.jpg");
Path moveto = FileSystems.getDefault().getPath("C:/rafaelnadal/photos/rafa_2.jpg");
try {
     Files.move(movefrom, moveto, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
     System.err.println(e);
}

可以使用resolve方法,目标目录的文件名和源目录的文件名相同。
Path movefrom = FileSystems.getDefault().getPath("C:/rafaelnadal/rafa_2.jpg");
Path moveto_dir = FileSystems.getDefault().getPath("C:/rafaelnadal/photos");
try {
     Files.move(movefrom, moveto_dir.resolve(movefrom.getFileName()),  StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
     System.err.println(e);
}

  • 4.4.4 重命名文件
Path movefrom = FileSystems.getDefault().getPath("C:/rafaelnadal/photos/rafa_2.jpg");
try {
     Files.move(movefrom, movefrom.resolveSibling("rafa_2_renamed.jpg"), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
     System.err.println(e);
}

  • 5 递归操作 Walks
  • 5.1 FileVisitor接口
•   FileVisitResult.CONTINUE: This visit result indicates that the traversal process should continue. It can be translated into different actions depending on which FileVisitor method is returned. For example, the traversal process may continue by visiting the next file, visiting a directory’s entries, or skipping a failure.
•   FileVisitResult.SKIP_SIBLINGS: This visit result indicates that the traversal process should continue without visiting the siblings of this file or directory.
•   FileVisitResult.SKIP_SUBTREE: This visit result indicates that the traversal process should  continue without visiting the rest of the entries in this directory.
•   FileVisitResult.TERMINATE: This visit result indicates that the traversal process should terminate. 

The constants of this enum type can be iterated as follows:
for (FileVisitResult constant : FileVisitResult.values())
System.out.println(constant);

  • 5.1.1 FileVisitor.visitFile()方法 
      The  visitFile() method is invoked for a file in a directory.
     
       For example, when searching for a file, this method should return   CONTINUE until the file is found (or the tree is completely traversed) and   TERMINATE after the file is found. 
      When this method is invoked, it receives a reference to the file and the file’s basic attributes. If an I/O error occurs, then it throws an  IOException exception. The following is the signature of this method:

FileVisitResult visitFile(T file, BasicFileAttributes attrs) throws IOException
  • 5.1.2 FileVisitor.preVisitDirectory()方法
The  preVisitDirectory() method is invoked for a directory before visiting its entries. The entries will be visited if the method returns   CONTINUE and will not be visited if it returns   SKIP_SUBTREE (the latter visit result is meaningful only when it is returned from this method). Also, you can skip visiting the siblings of this file or directory (and any descendants) by returning the   SKIP_SIBLINGS result.

FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs) throws IOException

  • 5.1.3 FileVisitor.postVisitDirectory()方法
     postVisitDirectory()方法在目录的所有的条目访问之后或者异常终止时发生。   
FileVisitResult postVisitDirectory(T dir, IOException exc) throws IOException

  • 5.1.4 FileVisitor.visitFileFailed()
visitFileFailed方法在文件不能被访问时调用,比如目录不能打开,文件属性不可读等。
FileVisitResult visitFileFailed(T file, IOException exc) throws IOException
  • 5.2 SimpleFileVisitorl类
public  class  SimpleFileVisitor <T>  implements  FileVisitor<T> {
     /**
     * Initializes a new instance of this class.
     */
     protected  SimpleFileVisitor() {
    }

     /**
     * Invoked for a directory before entries in the directory are visited.
     *
     *  <p>  Unless overridden, this method returns  {@link FileVisitResult#CONTINUE
     * CONTINUE}  .
     */
     @Override
     public  FileVisitResult preVisitDirectory(T  dir , BasicFileAttributes  attrs )
         throws  IOException
    {
        Objects. requireNonNull( dir  );
        Objects. requireNonNull( attrs  );
         return  FileVisitResult.  CONTINUE ;
    }

     /**
     * Invoked for a file in a directory.
     *
     *  <p>  Unless overridden, this method returns  {@link FileVisitResult#CONTINUE
     * CONTINUE}  .
     */
     @Override
     public  FileVisitResult visitFile(T  file , BasicFileAttributes  attrs )
         throws  IOException
    {
        Objects. requireNonNull( file  );
        Objects. requireNonNull( attrs  );
         return  FileVisitResult.  CONTINUE ;
    }

     /**
     * Invoked for a file that could not be visited.
     *
     *  <p>  Unless overridden, this method re  - throws the I/O exception that prevented
     * the file from being visited.
     */
     @Override
     public  FileVisitResult visitFileFailed(T  file , IOException  exc )
         throws  IOException
    {
        Objects. requireNonNull( file  );
         throw  exc ;
    }

     /**
     * Invoked for a directory after entries in the directory, and all of their
     * descendants, have been visited.
     *
     *  <p>  Unless overridden, this method returns  {@link FileVisitResult#CONTINUE
     * CONTINUE}  if the directory iteration completes without an I/O exception;
     * otherwise this method re  - throws the I/O exception that caused the iteration
     * of the directory to terminate prematurely.
     */
     @Override
     public  FileVisitResult postVisitDirectory(T  dir , IOException  exc )
         throws  IOException
    {
        Objects. requireNonNull( dir  );
         if  ( exc  !=  null )
             throw  exc ;
         return  FileVisitResult.  CONTINUE ;
    }
}

假如不想实现FileVisitor的所有接口,可以继承SimpleFileVisitor接口。例如:
class ListTree extends SimpleFileVisitor<Path> {
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
     System.out.println("Visited directory: " + dir.toString());
     return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file, IOException exc) {
     System.out.println(exc);
     return FileVisitResult.CONTINUE;
}
}

  • 5.3 开启递归进程
Path listDir = Paths.get("C:/rafaelnadal"); //define the starting file tree
ListTree walk = new ListTree(); //instantiate the walk
try{
     Files.walkFileTree(listDir, walk); //start the walk
} catch(IOException e){
     System.err.println(e);
}

限制递归的深度:
Path listDir = Paths.get("C:/rafaelnadal"); //define the starting file
ListTree walk = new ListTree(); //instantiate the walk
EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS); //follow links
try{
     Files.walkFileTree(listDir, opts, Integer. MAX_VALUE, walk); //start the walk
} catch(IOException e){
     System.err.println(e);
}

walkFileTree(start, visitor) 等价于: walkFileTree(start, EnumSet.noneOf(FileVisitOption.class), Integer.MAX_VALUE, visitor) 
  • 5.4 常用Walks
  • 5.4.1文件查找 
(1)按名字查找
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;

/**
* Created by ad on 2015/3/18.
*/
public class Search implements FileVisitor {
    private final Path searchedFile;
    public boolean found;

    public Search(Path searchedFile) {
        this.searchedFile = searchedFile;
        this.found = false;
    }

    void search(Path file) throws IOException {
        Path name = file.getFileName();
        if (name != null && name.equals(searchedFile)) {
            System.out.println("Searched file was found: " + searchedFile +
                    " in " + file.toRealPath().toString());
            found = true;
        }
    }

    @Override
    public FileVisitResult postVisitDirectory(Object dir, IOException exc)
            throws IOException {
        System.out.println("Visited: " + (Path) dir);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs)
            throws IOException {
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
            throws IOException {
        search((Path) file);
        if (!found) {
            return FileVisitResult.CONTINUE;
        } else {
            return FileVisitResult.TERMINATE;
        }
    }

    @Override
    public FileVisitResult visitFileFailed(Object file, IOException exc)
            throws IOException {
        //report an error if necessary
        return FileVisitResult.CONTINUE;
    }
}

class Main {
    public static void main(String[] args) throws IOException {
        Path searchFile = Paths.get("rafa_1.jpg");
        Search walk = new Search(searchFile);
        EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories();
        for (Path root : dirs) {
            if (!walk.found) {
                Files.walkFileTree(root, opts, Integer.MAX_VALUE, walk);
            }
        }
        if (!walk.found) {
            System.out.println("The file " + searchFile + " was not found!");
        }
    }
}

(2)Glob Pattern模式查找
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;

/**
* Created by ad on 2015/3/18.
*/
public class GlobSearchTest {
    public static void main(String[] args) throws IOException {
        String glob = "*.jpg";
        Path fileTree = Paths.get("C:/temp/");
        Search walk = new Search(glob);
        EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        Files.walkFileTree(fileTree, opts, Integer.MAX_VALUE, walk);
    }


   private static  class Search implements FileVisitor {
        private final PathMatcher matcher;
        public Search(String glob) {
            matcher = FileSystems.getDefault().getPathMatcher("glob:" + glob);
        }
        void search(Path file) throws IOException {
            Path name = file.getFileName();
            if (name != null && matcher.matches(name)) {
                System.out.println("Searched file was found: " + name +
                        " in " + file.toRealPath().toString());
            }
        }
        @Override
        public FileVisitResult postVisitDirectory(Object dir, IOException exc)
                throws IOException {
            System.out.println("Visited: " + (Path) dir);
            return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs)
                throws IOException {
            return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
                throws IOException {
            search((Path) file);
            return FileVisitResult.CONTINUE;
        }
        @Override
        public FileVisitResult visitFileFailed(Object file, IOException exc)
                throws IOException {
            //report an error if necessary
            return FileVisitResult.CONTINUE;
        }
    }
}

(3)基于文件大小
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;

class Search implements FileVisitor {

     private final PathMatcher matcher;
     private final long accepted_size;

     public Search(String glob, long accepted_size) {
          matcher = FileSystems.getDefault().getPathMatcher("glob:" + glob);
          this.accepted_size = accepted_size;
     }

     void search(Path file) throws IOException {
          Path name = file.getFileName();
          long size = (Long) Files.getAttribute(file, "basic:size");
          if (name != null && matcher.matches(name) && size <= accepted_size) {
               System.out.println("Searched file was found: " + name + " in " +
               file.toRealPath().toString() + " size (bytes):" + size);
           }
     }

     @Override
     public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException {
          System.out.println("Visited: " + (Path) dir);
          return FileVisitResult.CONTINUE;
     }

     @Override
     public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException {
          return FileVisitResult.CONTINUE;
     }

     @Override
     public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException {
          search((Path) file);
          return FileVisitResult.CONTINUE;
     }

     @Override
     public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException {
          //report an error if necessary
          return FileVisitResult.CONTINUE;
       }
}
class Main {
     public static void main(String[] args) throws IOException {
          String glob = "*.jpg";
          long size = 102400; //100 kilobytes in bytes
          Path fileTree = Paths.get("C:/rafaelnadal/");
          Search walk = new Search(glob, size);
          EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
          Files.walkFileTree(fileTree, opts, Integer.MAX_VALUE, walk);
     }
}
(4)基于内容查找
 字符串文件的查找,一般采用如下的代码片段:

String words="Rafael Nadal,tennis,winner of Roland Garros,BNP Paribas tournament draws";
ArrayList<String> wordsarray = new ArrayList<>();

StringTokenizer st = new StringTokenizer(words, ",");
while (st.hasMoreTokens()) {
     wordsarray.add(st.nextToken());
}

//search text
private boolean searchText(String text) {
     boolean flag = false;
     for (int j = 0; j < wordsarray.size(); j++) {
          if ((text.toLowerCase()).contains(wordsarray.get(j).toLowerCase())) {
               flag = true;
               break;
          }
     }
     return flag;
}


  1)PDF
 <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.5</version>
  </dependency>
  <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>1.8.8</version>
</dependency>


import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.PDFTextStripper;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;

 
    //search in PDF files using iText library
    boolean searchInPDF_iText(String file) {
        PdfReader reader = null;
        boolean flag = false;
        try {
            reader = new PdfReader(file);
            int n = reader.getNumberOfPages();
            OUTERMOST:
            for (int i = 1; i <= n; i++) {
                String str = PdfTextExtractor.getTextFromPage(reader, i);
                flag = searchText(str);
                if (flag) {
                    break OUTERMOST;
                }
            }
        } catch (Exception e) {
        } finally {
            if (reader != null) {
                reader.close();
            }
            return flag;
        }
    }

    //search in PDF files using pdfbox library
    boolean searchInPDF_PDFBox(String file) {
        PDFParser parser = null;
        String parsedText = null;
        PDFTextStripper pdfStripper = null;
        PDDocument pdDoc = null;
        COSDocument cosDoc = null;
        boolean flag = false;
        int page = 0;
        File pdf = new File(file);
        try {
            parser = new PDFParser(new FileInputStream(pdf));
            parser.parse();
            cosDoc = parser.getDocument();
            pdfStripper = new PDFTextStripper();
            pdDoc = new PDDocument(cosDoc);
            OUTERMOST:
            while (page < pdDoc.getNumberOfPages()) {
                page++;
                pdfStripper.setStartPage(page);
                pdfStripper.setEndPage(page + 1);
                parsedText = pdfStripper.getText(pdDoc);
                flag = searchText(parsedText);
                if (flag) {
                    break OUTERMOST;
                }
            }
        } catch (Exception e) {
        } finally {
            try {
                if (cosDoc != null) {
                    cosDoc.close();
                }
                if (pdDoc != null) {
                    pdDoc.close();
                }
            } catch (Exception e) {
            }
            return flag;
        }
    }

2)Microsoft Word, Excel, and PowerPoint
 <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.11</version>
  </dependency
     <!--用于ppt之类的扩展-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.11</version>
        </dependency>

import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.Notes;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.model.TextRun;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;

/**
* Created by ad on 2015/3/18.
*/
public class MSTest {

    boolean searchInWord(String file) {
        POIFSFileSystem fs = null;
        boolean flag = false;
        try {
            fs = new POIFSFileSystem(new FileInputStream(file));
            HWPFDocument doc = new HWPFDocument(fs);
            WordExtractor we = new WordExtractor(doc);
            String[] paragraphs = we.getParagraphText();
            OUTERMOST:
            for (int i = 0; i < paragraphs.length; i++) {
                flag = searchText(paragraphs[i]);
                if (flag) {
                    break OUTERMOST;
                }
            }
        } catch (Exception e) {
        } finally {
            return flag;
        }
    }

    boolean searchInExcel(String file) {
        Row row;
        Cell cell;
        String text;
        boolean flag = false;
        InputStream xls = null;
        try {
            xls = new FileInputStream(file);
            HSSFWorkbook wb = new HSSFWorkbook(xls);
            int sheets = wb.getNumberOfSheets();
            OUTERMOST:
            for (int i = 0; i < sheets; i++) {
                HSSFSheet sheet = wb.getSheetAt(i);
                Iterator<Row> row_iterator = sheet.rowIterator();
                while (row_iterator.hasNext()) {
                    row = (Row) row_iterator.next();
                    Iterator<Cell> cell_iterator = row.cellIterator();
                    while (cell_iterator.hasNext()) {
                        cell = cell_iterator.next();
                        int type = cell.getCellType();
                        if (type == HSSFCell.CELL_TYPE_STRING) {
                            text = cell.getStringCellValue();
                            flag = searchText(text);
                            if (flag) {
                                break OUTERMOST;
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
        } finally {
            try {
                if (xls != null) {
                    xls.close();
                }
            } catch (IOException e) {
            }
            return flag;
        }
    }

    boolean searchInPPT(String file) {
        boolean flag = false;
        InputStream fis = null;
        String text;
        try {
            fis = new FileInputStream(new File(file));
            POIFSFileSystem fs = new POIFSFileSystem(fis);
            HSLFSlideShow show = new HSLFSlideShow(fs);
            SlideShow ss = new SlideShow(show);
            Slide[] slides = ss.getSlides();
            OUTERMOST:
            for (int i = 0; i < slides.length; i++) {
                TextRun[] runs = slides[i].getTextRuns();
                for (int j = 0; j < runs.length; j++) {
                    TextRun run = runs[j];
                    if (run.getRunType() == TextHeaderAtom.TITLE_TYPE) {
                        text = run.getText();
                    } else {
                        text = run.getRunType() + " " + run.getText();
                    }
                    flag = searchText(text);
                    if (flag) {
                        break OUTERMOST;
                    }
                }
                Notes notes = slides[i].getNotesSheet();
                if (notes != null) {
                    runs = notes.getTextRuns();
                    for (int j = 0; j < runs.length; j++) {
                        text = runs[j].getText();
                        flag = searchText(text);
                        if (flag) {
                            break OUTERMOST;
                        }
                    }
                }
            }
        } catch (IOException e) {
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
            }
            return flag;
        }
    }

}



3)文本文件查找
boolean searchInText(Path file) {
     boolean flag = false;
     Charset charset = Charset.forName("UTF-8");
     try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
          String line = null;
          OUTERMOST:
          while ((line = reader.readLine()) != null) {
               flag = searchText(line);
               if (flag) {
                    break OUTERMOST;
               }
          }
     } catch (IOException e) {
     } finally {
          return flag;
     }
}

完整的例子:
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.parser.PdfTextExtractor;
import org.apache.pdfbox.cos.COSDocument;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.PDFTextStripper;
import org.apache.poi.hslf.HSLFSlideShow;
import org.apache.poi.hslf.model.Notes;
import org.apache.poi.hslf.model.Slide;
import org.apache.poi.hslf.model.TextRun;
import org.apache.poi.hslf.record.TextHeaderAtom;
import org.apache.poi.hslf.usermodel.SlideShow;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hwpf.HWPFDocument;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.StringTokenizer;

class Search implements FileVisitor {
    ArrayList<String> wordsarray = new ArrayList<>();
    ArrayList<String> documents = new ArrayList<>();
    boolean found = false;

    public Search(String words) {
        wordsarray.clear();
        documents.clear();
        StringTokenizer st = new StringTokenizer(words, ",");
        while (st.hasMoreTokens()) {
            wordsarray.add(st.nextToken().trim());
        }
    }

    void search(Path file) throws IOException {
        found = false;
        String name = file.getFileName().toString();
        int mid = name.lastIndexOf(".");
        String ext = name.substring(mid + 1, name.length());
        if (ext.equalsIgnoreCase("pdf")) {
            found = searchInPDF_iText(file.toString());
            if (!found) {
                found = searchInPDF_PDFBox(file.toString());
            }
        }
        if (ext.equalsIgnoreCase("doc") || ext.equalsIgnoreCase("docx")) {
            found = searchInWord(file.toString());
        }
        if (ext.equalsIgnoreCase("ppt")) {
            searchInPPT(file.toString());
        }
        if (ext.equalsIgnoreCase("xls")) {
            searchInExcel(file.toString());
        }
        if ((ext.equalsIgnoreCase("txt")) || (ext.equalsIgnoreCase("xml")
                || ext.equalsIgnoreCase("html"))
                || ext.equalsIgnoreCase("htm") || ext.equalsIgnoreCase("xhtml")
                || ext.equalsIgnoreCase("rtf")) {
            searchInText(file);
        }
        if (found) {
            documents.add(file.toString());
        }
    }

    //search in text files
    boolean searchInText(Path file) {
        boolean flag = false;
        Charset charset = Charset.forName("UTF-8");
        try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
            String line = null;
            OUTERMOST:
            while ((line = reader.readLine()) != null) {
                flag = searchText(line);
                if (flag) {
                    break OUTERMOST;
                }
            }
        } catch (IOException e) {
        } finally {
            return flag;
        }
    }



    //search in Excel files
    boolean searchInExcel(String file) {
        Row row;
        Cell cell;
        String text;
        boolean flag = false;
        InputStream xls = null;
        try {
            xls = new FileInputStream(file);
            HSSFWorkbook wb = new HSSFWorkbook(xls);
            int sheets = wb.getNumberOfSheets();

            OUTERMOST:
            for (int i = 0; i < sheets; i++) {
                HSSFSheet sheet = wb.getSheetAt(i);
                Iterator<Row> row_iterator = sheet.rowIterator();
                while (row_iterator.hasNext()) {
                    row = (Row) row_iterator.next();
                    Iterator<Cell> cell_iterator = row.cellIterator();
                    while (cell_iterator.hasNext()) {
                        cell = cell_iterator.next();
                        int type = cell.getCellType();
                        if (type == HSSFCell.CELL_TYPE_STRING) {
                            text = cell.getStringCellValue();
                            flag = searchText(text);
                            if (flag) {
                                break OUTERMOST;
                            }
                        }
                    }
                }
            }
        } catch (IOException e) {
        } finally {
            try {
                if (xls != null) {
                    xls.close();
                }
            } catch (IOException e) {
            }
            return flag;
        }
    }


//search in PowerPoint files
    boolean searchInPPT(String file) {
        boolean flag = false;
        InputStream fis = null;
        String text;
        try {
            fis = new FileInputStream(new File(file));
            POIFSFileSystem fs = new POIFSFileSystem(fis);
            HSLFSlideShow show = new HSLFSlideShow(fs);
            SlideShow ss = new SlideShow(show);
            Slide[] slides = ss.getSlides();
            OUTERMOST:
            for (int i = 0; i < slides.length; i++) {

                TextRun[] runs = slides[i].getTextRuns();
                for (int j = 0; j < runs.length; j++) {
                    TextRun run = runs[j];
                    if (run.getRunType() == TextHeaderAtom.TITLE_TYPE) {
                        text = run.getText();
                    } else {
                        text = run.getRunType() + " " + run.getText();
                    }
                    flag = searchText(text);
                    if (flag) {
                        break OUTERMOST;
                    }
                }
                Notes notes = slides[i].getNotesSheet();
                if (notes != null) {
                    runs = notes.getTextRuns();
                    for (int j = 0; j < runs.length; j++) {
                        text = runs[j].getText();
                        flag = searchText(text);
                        if (flag) {
                            break OUTERMOST;
                        }
                    }
                }
            }
        } catch (IOException e) {
        } finally {
            try {
                if (fis != null) {
                    fis.close();
                }
            } catch (IOException e) {
            }
            return flag;
        }
    }


    //search in Word files
    boolean searchInWord(String file) {
        POIFSFileSystem fs = null;
        boolean flag = false;
        try {
            fs = new POIFSFileSystem(new FileInputStream(file));
            HWPFDocument doc = new HWPFDocument(fs);

            WordExtractor we = new WordExtractor(doc);
            String[] paragraphs = we.getParagraphText();
            OUTERMOST:
            for (int i = 0; i < paragraphs.length; i++) {
                flag = searchText(paragraphs[i]);
                if (flag) {
                    break OUTERMOST;
                }
            }
        } catch (Exception e) {
        } finally {
            return flag;
        }
    }

    //search in PDF files using PDFBox library
    boolean searchInPDF_PDFBox(String file) {
        PDFParser parser = null;
        String parsedText = null;
        PDFTextStripper pdfStripper = null;
        PDDocument pdDoc = null;
        COSDocument cosDoc = null;
        boolean flag = false;
        int page = 0;
        File pdf = new File(file);
        try {
            parser = new PDFParser(new FileInputStream(pdf));
            parser.parse();
            cosDoc = parser.getDocument();
            pdfStripper = new PDFTextStripper();
            pdDoc = new PDDocument(cosDoc);
            OUTERMOST:
            while (page < pdDoc.getNumberOfPages()) {
                page++;
                pdfStripper.setStartPage(page);
                pdfStripper.setEndPage(page + 1);
                parsedText = pdfStripper.getText(pdDoc);
                flag = searchText(parsedText);
                if (flag) {
                    break OUTERMOST;
                }
            }

        } catch (Exception e) {
        } finally {
            try {
                if (cosDoc != null) {
                    cosDoc.close();
                }
                if (pdDoc != null) {
                    pdDoc.close();
                }
            } catch (Exception e) {
            }
            return flag;
        }
    }

    //search in PDF files using iText library
    boolean searchInPDF_iText(String file) {
        PdfReader reader = null;
        boolean flag = false;
        try {
            reader = new PdfReader(file);
            int n = reader.getNumberOfPages();
            OUTERMOST:
            for (int i = 1; i <= n; i++) {
                String str = PdfTextExtractor.getTextFromPage(reader, i);
                flag = searchText(str);
                if (flag) {
                    break OUTERMOST;
                }
            }
        } catch (Exception e) {
        } finally {
            if (reader != null) {
                reader.close();
            }
            return flag;
        }
    }


    //search text
    private boolean searchText(String text) {
        boolean flag = false;
        for (int j = 0; j < wordsarray.size(); j++) {
            if ((text.toLowerCase()).contains(wordsarray.get(j).toLowerCase())) {
                flag = true;

                break;
            }
        }
        return flag;
    }

    @Override
    public FileVisitResult postVisitDirectory(Object dir, IOException exc)
            throws IOException {
        System.out.println("Visited: " + (Path) dir);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs)
            throws IOException {
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
            throws IOException {
        search((Path) file);
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Object file, IOException exc)
            throws IOException {
//report an error if necessary
        return FileVisitResult.CONTINUE;
    }
}

public class SearchCompleteTest {
    public static void main(String[] args) throws IOException {
        String words = "Platform independent, Btrace, java";
        Search walk = new Search(words);
        EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        Iterable<Path> dirs = FileSystems.getDefault().getRootDirectories();
        for (Path root : dirs) {
            Files.walkFileTree(root, opts, Integer.MAX_VALUE, walk);
        }
        System.out.println("____________________________________________________________");
        for(String path_string: walk.documents){
            System.out.println(path_string);
        }
        System.out.println("____________________________________________________________");
    }

}
  • 5.4.2 文件删除 
原则:
• 删除目录前删除所有的文件。 
•  在visitFile()方法中删除每个文件。 
•  在postVisitDirectory()方法中删除目录。 
•  如果文件不能被访问,则在visitFileFailed()方法中返回 FileVisitResult.CONTINUE或者TERMINATE。
•  不建议删除符号链接。
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;

/**
* Created by ad on 2015/3/20.
*/
public class DeleteDirectoryTest {

    public static void main(String[] args) throws IOException {
        Path directory = Paths.get("C:/rafaelnadal");
        DeleteDirectory walk = new DeleteDirectory();
        EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
        Files.walkFileTree(directory, opts, Integer.MAX_VALUE, walk);
    }
}

class DeleteDirectory implements FileVisitor {

    boolean deleteFileByFile(Path file) throws IOException {
        return Files.deleteIfExists(file);
    }

    @Override
    public FileVisitResult postVisitDirectory(Object dir, IOException exc)
            throws IOException {
        if (exc == null) {
            System.out.println("Visited: " + (Path) dir);
            boolean success = deleteFileByFile((Path) dir);
            if (success) {
                System.out.println("Deleted: " + (Path) dir);
            } else {
                System.out.println("Not deleted: " + (Path) dir);
            }
        } else {
            throw exc;
        }
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs)
            throws IOException {
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFile(Object file, BasicFileAttributes attrs)
            throws IOException {
        boolean success = deleteFileByFile((Path) file);
        if (success) {
            System.out.println("Deleted: " + (Path) file);
        } else {
            System.out.println("Not deleted: " + (Path) file);
        }
        return FileVisitResult.CONTINUE;
    }

    @Override
    public FileVisitResult visitFileFailed(Object file, IOException exc)
            throws IOException {
          //report an error if necessary
        return FileVisitResult.CONTINUE;
    }
}

Note Sending the deleted files to the recycle bin can be accomplished by using JNI to invoke Windows API SHFileOperation() method. Check out David Shay’s post at www.jroller.com/ethdsy/entry/send_to_recycle_bin  for more details.
 如果是Dos或者Open File Dialog Box,则不会存入回收站。
//Send to Recycle Bin
JNIEXPORT void JNICALL Java_JNIServerInterface_sendToRecycleBin
  (JNIEnv *env, jclass, jstring fileName)
{
    LPCTSTR src;
    SHFILEOPSTRUCT opFile;
    
    src = (LPTSTR)env->GetStringUTFChars (fileName, NULL);

    HANDLE file = CreateFile (src, GENERIC_READ, FILE_SHARE_READ, NULL, 
                              OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
    
    // Checks if file exists
    if (file == INVALID_HANDLE_VALUE)
    {
        env->ReleaseStringUTFChars (fileName, src);
        env->ThrowNew (env->FindClass ("java/io/IOException"),
            "Error while opening file.");
        return;
    }
    
    CloseHandle (file);

    
    int len = strlen(src)+2;
    char* csrc = new char[len];
    strcpy(csrc, src);
    csrc[len-1] = csrc[len-2] = 0;

    ZeroMemory(&opFile, sizeof(opFile));
    opFile.wFunc = FO_DELETE;
    opFile.pFrom = csrc;
    opFile.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_SILENT;
    
    if (SHFileOperation (&opFile))
    {
        env->ReleaseStringUTFChars (fileName, src);
        delete[] csrc;
        env->ThrowNew (env->FindClass ("java/io/IOException"),
            "Error while opening file.");
    }
    
    env->ReleaseStringUTFChars (fileName, src);
    delete[] csrc;
}
  • 5.4.3 文件复制 
原则:
•  在复制文件前,需要复制所在的目录。 可以在preVisitDirectory() 中实现.
•  visitFile()方法用于复制文件。 
•  在复制文件或者目录时,考虑使用REPLACE_EXISTING 和COPY_ATTRIBUTES 选项.
•  如果需要保留源目录的属性,可以在postVisitDirectory() 方法中实现.
•  如果使用了FOLLOW_LINKS选项,并且文件树有根循环链接到父目录,则会在visitFileFailed()方法中报FileSystemLoopException异常
•  如果文件不能被访问,则在visitFileFailed()方法中返回 FileVisitResult.CONTINUE或者TERMINATE。 
• 可以使用 FOLLOW_LINKS 选项用于符号链接.

import java.nio.file.FileSystemLoopException;
import java.nio.file.attribute.FileTime;
import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;

class CopyTree implements FileVisitor {
     private final Path copyFrom;
     private final Path copyTo;

     public CopyTree(Path copyFrom, Path copyTo) {
          this.copyFrom = copyFrom;
          this.copyTo = copyTo;
     }

     static void copySubTree(Path copyFrom, Path copyTo) throws IOException {
          try {
               Files.copy(copyFrom, copyTo, REPLACE_EXISTING, COPY_ATTRIBUTES);
            } catch (IOException e) {
               System.err.println("Unable to copy " + copyFrom + " [" + e + "]");
          }
}


@Override
public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException {
     if (exc == null) {
               Path newdir = copyTo.resolve(copyFrom.relativize((Path) dir));
               try {
                    FileTime time = Files.getLastModifiedTime((Path) dir);
                    Files.setLastModifiedTime(newdir, time);
               } catch (IOException e) {
               System.err.println("Unable to copy all attributes to: " + newdir+" ["+e+ "]");
          }
          } else {
          throw exc;
     }
     return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs)throws IOException {
     System.out.println("Copy directory: " + (Path) dir);
     Path newdir = copyTo.resolve(copyFrom.relativize((Path) dir));
     try {
           Files.copy((Path) dir, newdir, REPLACE_EXISTING, COPY_ATTRIBUTES);
     } catch (IOException e) {
          System.err.println("Unable to create " + newdir + " [" + e + "]");
          return FileVisitResult.SKIP_SUBTREE;
     }
     return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException {
     System.out.println("Copy file: " + (Path) file);
     copySubTree((Path) file, copyTo.resolve(copyFrom.relativize((Path) file)));
     return FileVisitResult.CONTINUE;
}

@Override
public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException {
     if (exc instanceof FileSystemLoopException) {
          System.err.println("Cycle was detected: " + (Path) file);
     } else {
          System.err.println("Error occurred, unable to copy:" +(Path) file+" ["+ exc +"]");
     }
     return FileVisitResult.CONTINUE;
     }
}

class Main {
     public static void main(String[] args) throws IOException {
          Path copyFrom = Paths.get("C:/rafaelnadal");
          Path copyTo = Paths.get("C:/rafaelnadal_copy");
          CopyTree walk = new CopyTree(copyFrom, copyTo);
          EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
          Files.walkFileTree(copyFrom, opts, Integer.MAX_VALUE, walk);
     }
}

  • 5.4.4 文件移动
两种方式:Files.move(),  Files.copy(), 和Files.delete(), 或者Files.copy() 和Files.delete().
原则:
•  Before you move any files from a directory, you must move the directory itself. Since nonempty directories cannot be moved (only empty directories can be moved), you need to use the  Files.copy() method, which will copy an empty directory instead. This task must be accomplished in the  preVisitDirectory() method.
•  The  visitFile() method is the perfect place to move each file. For this you can use the  Files.move() method, or  Files.copy() combined with  Files.delete().
•  After all files from a source directory are moved into the target directory, you need to call  Files.delete() to delete the source directory, which, at this moment, should be empty. This task must be accomplished in the  postVisitDirectory() method.
•  When you copy a file or directory, you need to decide whether or not you want to use the  REPLACE_EXISTING and  COPY_ATTRIBUTES options. Moreover, when you move a file or directory, you need to decide if  ATOMIC_MOVE is needed.
•  If you want to preserve the attributes of the source directory, you need to do that after the files have been moved, in the  postVisitDirectory() method. Some attributes, such as  lastModifiedTime, should be extracted in the preVisitDirectory() method and stored until they are set in
postVisitDirectory(). The reason is that after you move a file from the source directory, the directory content has changed and the initial last modified time is overwritten by the new date.
•  If a file cannot be visited, the  visitFileFailed() method should return FileVisitResult.CONTINUE or  TERMINATE, depending on your decision.
•  The move process can follow symbolic links if you specify the  FOLLOW_LINKS option. Keep in mind that moving a symbolic link moves the link itself, not the target of that link.

import java.io.IOException;
import java.nio.file.FileVisitOption;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.attribute.FileTime;
import java.util.EnumSet;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static java.nio.file.StandardCopyOption.COPY_ATTRIBUTES;
import static java.nio.file.StandardCopyOption.ATOMIC_MOVE;

class MoveTree implements FileVisitor {
     private final Path moveFrom;
     private final Path moveTo;
     static FileTime time = null;
     public MoveTree(Path moveFrom, Path moveTo) {
          this.moveFrom = moveFrom;
          this.moveTo = moveTo;
     }

     static void moveSubTree(Path moveFrom, Path moveTo) throws IOException {
          try {
               Files.move(moveFrom, moveTo, REPLACE_EXISTING, ATOMIC_MOVE);
          } catch (IOException e) {
               System.err.println("Unable to move " + moveFrom + " [" + e + "]");
          }
     }


     @Override
     public FileVisitResult postVisitDirectory(Object dir, IOException exc) throws IOException {
          Path newdir = moveTo.resolve(moveFrom.relativize((Path) dir));
          try {
               Files.setLastModifiedTime(newdir, time);
               Files.delete((Path) dir);
          } catch (IOException e) {
               System.err.println("Unable to copy all attributes to: " + newdir+" [" + e + "]");
          }
          return FileVisitResult.CONTINUE;
     }

     @Override
     public FileVisitResult preVisitDirectory(Object dir, BasicFileAttributes attrs) throws IOException {
          System.out.println("Move directory: " + (Path) dir);
          Path newdir = moveTo.resolve(moveFrom.relativize((Path) dir));
          try {
               Files.copy((Path) dir, newdir, REPLACE_EXISTING, COPY_ATTRIBUTES);
               time = Files.getLastModifiedTime((Path) dir);
          } catch (IOException e) {
               System.err.println("Unable to move " + newdir + " [" + e + "]");
               return FileVisitResult.SKIP_SUBTREE;
          }
          return FileVisitResult.CONTINUE;
     }


     @Override
     public FileVisitResult visitFile(Object file, BasicFileAttributes attrs) throws IOException {
          System.out.println("Move file: " + (Path) file);
          moveSubTree((Path) file, moveTo.resolve(moveFrom.relativize((Path) file)));
          return FileVisitResult.CONTINUE;
     }

     @Override
     public FileVisitResult visitFileFailed(Object file, IOException exc) throws IOException {
          return FileVisitResult.CONTINUE;
     }
}
class Main {
     public static void main(String[] args) throws IOException {
          Path moveFrom = Paths.get("C:/rafaelnadal");
          Path moveTo = Paths.get("C:/ATP/players/rafaelnadal");
          MoveTree walk = new MoveTree(moveFrom, moveTo);
          EnumSet opts = EnumSet.of(FileVisitOption.FOLLOW_LINKS);
          Files.walkFileTree(moveFrom, opts, Integer.MAX_VALUE, walk);
     }
}

move可以使用下面方法替换:
static void moveSubTree(Path moveFrom, Path moveTo) throws IOException {
     try {
          Files.copy(moveFrom, moveTo, REPLACE_EXISTING, COPY_ATTRIBUTES);
          Files.delete(moveFrom);
     } catch (IOException e) {
          System.err.println("Unable to move " + moveFrom + " [" + e + "]");
     }
}

  • 6 Watch Service API
      The Watch Service API was introduced in Java 7 (NIO.2) as a thread-safe service that is capable of watching objects for changes and events. The most common use is to monitor a directory for changes to its content through actions such as create, delete, and modify.
例如通过UE打开一个文件,如果在其他界面或工具修改了文件内容,则UE会提示你是否重新加载该文件。这就是著名的文件改变通知机制,在NIO.2中, 就是 Watch Service API.
  • 6.1 Watch Service API类
Watchable对象:实现了java.nio.file.Watchable接口的类的实例,NIO.2中指Path.
Event类型:This is the list of events we are interested in monitoring. Events trigger a notification only if they are specified in the register call. The standard supported events are represented by the java.nio.file.StandardWatchEventKinds class and include create, delete, and modify. This class implements the WatchEvent.Kind<T> interface.
Event modifier: This qualifies how a Watchable is registered with a WatchService. As of the time of this writing, NIO.2 does not define any standard modifiers.
Watcher: The watcher watches watchables! In our examples, the watcher is WatchService and it monitors the file system changes (the file system is a  FileSystem instance). As you will see, the WatchService will be created through  the FileSystem class. It will work away silently in the background watching the  registered Path.

  • 6.2 实现Watch Service
(1)创建WatchService
     WatchService watchService = FileSystems.getDefault().newWatchService();

(2)往Watch Service注册对象
监控的事件类型有:
•   StandardWatchEventKinds.ENTRY_CREATE:目录条目创建时触发.同时也包括例如重命名、Move等。 
•   StandardWatchEventKinds.ENTRY_DELETE:目录条目删除时触发. 也包括重命名、Move等。
•   StandardWatchEventKinds.ENTRY_MODIFY: 目录条目修改时触发. Which events constitute a modification is somewhat platform-specific, but actually modifying the contents of a file always triggers a modify event. On some platforms, changing attributes of files can also trigger this event.
•   StandardWatchEventKinds.OVERFLOW: Indicates that events might have been lost or discarded. You do not have to register for the OVERFLOW event to receive it.

Since the Path class implements the Watchable interface, it provides the Watchable.register() methods。

import static java.nio.file.StandardWatchEventKinds.*;


final Path path = Paths.get("C:/rafaelnadal");
WatchService watchService = FileSystems.getDefault().newWatchService();
.....
path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_MODIFY,  StandardWatchEventKinds.ENTRY_DELETE);
....
watchService.close();

(3)等待事件
while(true){
     //retrieve and process the incoming events
     …
}
Or it may be of the following type:
for(;;){
     //retrieve and process the incoming events
     …
}

(4)获取Watch key
//poll method, without arguments
while (true) {
     //retrieve and remove the next watch key
     final WatchKey key = watchService.poll();
     //the thread flow gets here immediately with an available key or a null value
     …
}
//poll method, with arguments
while (true) {
     //retrieve and remove the next watch key
     final WatchKey key = watchService.poll(10, TimeUnit.SECONDS);
     //the thread flow gets here immediately if a key is available, or after 10 seconds
     //with an available key or null value
     …
}

//take method
while (true) {
     //retrieve and remove the next watch key
     final WatchKey key = watchService.take();   //阻塞等待watch key
     //the thread flow gets here immediately if a key is available, or it will wait until a key is available, or the loop breaks
     …
}

Watch Key是有状态的:
•   Ready: When it is first created, a key is in the ready state, which means that it is ready to accept events.
•   Signaled: When a key is in the signaled state, it means that at least one event has occurred and the key was queued, so it is available to be retrieved by poll() or take() methods. (It is analogous to fishing: the key is the float, and the events are the fish. When you have a fish on the hook, the float (key) signals you to pull the line out of the water.) Once signaled, the key remains in this state until its reset() method is invoked to return the key to the ready state. If other events occur while the key is signaled, they are queued without requeuing the key itself (this never happens when fishing).
•   Invalid: When a key is in the invalid state, it means that it is no longer active. A key remains valid until either it is cancelled by explicitly calling the cancel() method, the directory becomes inaccessible, or the watch service is closed. You can test whether a key is valid by calling the WatchKey.isValid() method, which will return a corresponding boolean value.

  Note Watch keys are safe for use by multiple concurrent threads.

(5)检索Key的等待事件

public List<WatchEvent<?>> pollEvents()
Note The  pollEvents() method does not wait if there are no events pending, which sometimes may result in an empty  List.Watch events are immutable and thread-safe.

while (true) {

     //retrieve and remove the next watch key
     final WatchKey key = watchService.take();

     //get list of pending events for the watch key
     for (WatchEvent<?> watchEvent : key.pollEvents()) {
          …
     }
     …
}

(6)检索事件类型和数量
//get list of pending events for the watch key
for (WatchEvent<?> watchEvent : key.pollEvents()) {

     //get the kind of event (create, modify, delete)
     final Kind<?> kind = watchEvent.kind();

     //handle OVERFLOW event
     if (kind ==  StandardWatchEventKinds.OVERFLOW) {
          continue;
     }
     System.out.println(kind);
}
System.out.println(watchEvent.count());


Note If you ignore the registered event types, it is possible to receive an  OVERFLOW event. This kind of event can be ignored or handled, the choice of which is up to you.

(7)检索事件关联的文件名

final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
final Path filename = watchEventPath.context();
System.out.println(filename);

(8)Key重置为Ready状态

while(true){
     …
     //reset the key
     boolean valid = key.reset();

     //exit loop if the key is not valid (if the directory was deleted, for example)
     if (!valid) {
          break;
      }
}

Caution If you forget or fail to call the  reset() method, the key will not receive any further events!

(9)关闭Watch Service

try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
     …
}

(10)整合例子

import java.io.IOException;
import java.nio.file.*;

/**
* Created by ad on 2015/3/20.
*/
public class WatchRafaelNadal {

    public void watchRNDir(Path path) throws IOException, InterruptedException {

        try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
            path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
                    StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
            //start an infinite loop
            while (true) {

                 //retrieve and remove the next watch key
                final WatchKey key = watchService.take();

                //get list of pending events for the watch key
                for (WatchEvent<?> watchEvent : key.pollEvents()) {

                    //get the kind of event (create, modify, delete)
                    final WatchEvent.Kind<?> kind = watchEvent.kind();

                    //handle OVERFLOW event
                    if (kind == StandardWatchEventKinds.OVERFLOW) {
                        continue;
                    }

                    //get the filename for the event
                    final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
                    final Path filename = watchEventPath.context();

                    //print it out
                    System.out.println(kind + " -> " + filename);
                }

                //reset the key
                boolean valid = key.reset();
                //exit loop if the key is not valid (if the directory was deleted, for  example)

                if (!valid) {
                    break;
                }
            }
        }
    }


    public static void main(String[] args) {
        final Path path = Paths.get("C:/test");
        WatchRafaelNadal watch = new WatchRafaelNadal();
        try {
            watch.watchRNDir(path);
        } catch (IOException | InterruptedException ex) {
            System.err.println(ex);
        }
    }

}

测试步骤:
在C:/test目录下新建文件blahblah.txt
输出:
ENTRY_CREATE -> blahblah.txt
ENTRY_MODIFY -> blahblah.txt

删除文件blahblah.txt:
输出
ENTRY_DELETE -> blahblah.txt

  • 6.3 使用Watch Service的其他例子
  • 6.3.1 监控目录树
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.HashMap;
import java.util.Map;

/**
* Created by ad on 2015/3/20.
*/
public class WatchRecursiveRafaelNadal {

    private WatchService watchService;
    private final Map<WatchKey, Path> directories = new HashMap<>();

    private void registerPath(Path path) throws IOException {
        //register the received path
        WatchKey key = path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
                StandardWatchEventKinds.ENTRY_MODIFY, StandardWatchEventKinds.ENTRY_DELETE);
        //store the key and path
        directories.put(key, path);
    }

    private void registerTree(Path start) throws IOException {
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                    throws IOException {
                System.out.println("Registering:" + dir);
                registerPath(dir);
                return FileVisitResult.CONTINUE;
            }
        });
    }

    public void watchRNDir(Path start) throws IOException, InterruptedException {
        watchService = FileSystems.getDefault().newWatchService();

        registerTree(start);

        //start an infinite loop
        while (true) {
            //retrieve and remove the next watch key
            final WatchKey key = watchService.take();

            //get list of events for the watch key
            for (WatchEvent<?> watchEvent : key.pollEvents()) {

                //get the kind of event (create, modify, delete)
                final WatchEvent.Kind<?> kind = watchEvent.kind();

                //get the filename for the event
                final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
                final Path filename = watchEventPath.context();

                //handle OVERFLOW event
                if (kind == StandardWatchEventKinds.OVERFLOW) {
                    continue;
                }

                //handle CREATE event
                if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                    final Path directory_path = directories.get(key);
                    final Path child = directory_path.resolve(filename);
                    if (Files.isDirectory(child, LinkOption.NOFOLLOW_LINKS)) {
                        registerTree(child);
                    }
                }
                //print it out
                System.out.println(kind + " -> " + filename);
            }

            //reset the key
            boolean valid = key.reset();

            //remove the key if it is not valid
            if (!valid) {
                directories.remove(key);

                //there are no more keys registered
                if (directories.isEmpty()) {
                    break;
                }
            }
        }

        watchService.close();
    }


    public static void main(String[] args) {
        final Path path = Paths.get("C:/test");
        WatchRecursiveRafaelNadal watch = new WatchRecursiveRafaelNadal();
        try {
            watch.watchRNDir(path);
        } catch (IOException | InterruptedException ex) {
            System.err.println(ex);
        }
    }
}
  • 6.3.2检索Video Camera
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
* Created by ad on 2015/3/20.
*/
public class SecurityWatch {
    WatchService watchService;
    private void register(Path path, Kind<Path> kind) throws IOException {
        //register the directory with the watchService for Kind<Path> event
        path.register(watchService, kind);
    }
    public void watchVideoCamera(Path path) throws IOException, InterruptedException {
        watchService = FileSystems.getDefault().newWatchService();
       
        register(path, StandardWatchEventKinds.ENTRY_CREATE);
        //start an infinite loop
        OUTERMOST:
        while (true) {
            //retrieve and remove the next watch key
            final WatchKey key = watchService.poll(11, TimeUnit.SECONDS);
            if (key == null) {
                System.out.println("The video camera is jammed - security watch system is canceled!");
                break;
            } else {
                //get list of events for the watch key
                for (WatchEvent<?> watchEvent : key.pollEvents()) {
                    //get the kind of event (create, modify, delete)
                    final Kind<?> kind = watchEvent.kind();
                    //handle OVERFLOW event
                    if (kind == StandardWatchEventKinds.OVERFLOW) {
                        continue;
                    }
                    if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                        //get the filename for the event
                        final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
                        final Path filename = watchEventPath.context();
                        final Path child = path.resolve(filename);
                        if (Files.probeContentType(child).equals("image/jpeg")) {
                        //print out the video capture time
                            SimpleDateFormat dateFormat = new
                                    SimpleDateFormat("yyyy-MMM-dd HH:mm:ss");
                            System.out.println("Video capture successfully at: " +
                                    dateFormat.format(new Date()));
                        } else {
                            System.out.println("The video camera capture format failed!a  This could be a virus!");
                            break OUTERMOST;
                        }
                    }
                }
                //reset the key
                boolean valid = key.reset();
                //exit loop if the key is not valid
                if (!valid) {
                    break;
                }
            }
        }
        watchService.close();
    }


    public static void main(String[] args) {
        final Path path = Paths.get("C:/security");
        SecurityWatch watch = new SecurityWatch();
        try {
            watch.watchVideoCamera(path);
        } catch (IOException | InterruptedException ex) {
            System.err.println(ex);
        }
    }
}

  • 6.3.3 检索Printer Tray System
Note Java 7 recommends using the new   ThreadLocalRandom class for generating random numbers in multithreading cases. But I prefer the old  Random class because the new class seems to have a  bug; it generates the same numbers over multiple threads. If the bug has been resolved by the time you read this book, then you may want to use this line instead:  ThreadLocalRandom.current().nextInt(20000, 50000);
 
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.WatchEvent.Kind;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
* Created by ad on 2015/3/20.
*/
public class WatchPrinterTray {
    private final Map<Thread, Path> threads = new HashMap<>();

    public void watchTray(Path path) throws IOException, InterruptedException {
        try (WatchService watchService = FileSystems.getDefault().newWatchService()) {
            path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE,
                    StandardWatchEventKinds.ENTRY_DELETE);
           
            //start an infinite loop
            while (true) {

                //retrieve and remove the next watch key
                final WatchKey key = watchService.poll(10, TimeUnit.SECONDS);

                //get list of events for the watch key
                if (key != null) {
                    for (WatchEvent<?> watchEvent : key.pollEvents()) {

                        //get the filename for the event
                        final WatchEvent<Path> watchEventPath = (WatchEvent<Path>) watchEvent;
                        final Path filename = watchEventPath.context();

                        //get the kind of event (create, modify, delete)
                        final Kind<?> kind = watchEvent.kind();

                        //handle OVERFLOW event
                        if (kind == StandardWatchEventKinds.OVERFLOW) {
                            continue;
                        }
                        if (kind == StandardWatchEventKinds.ENTRY_CREATE) {
                            System.out.println("Sending the document to print ->" + filename);
                            Runnable task = new Print(path.resolve(filename));
                            Thread worker = new Thread(task);

                            //we can set the name of the thread
                            worker.setName(path.resolve(filename).toString());

                            //store the thread and the path
                            threads.put(worker, path.resolve(filename));

                           //start the thread, never call method run() direct
                            worker.start();
                        }
                        if (kind == StandardWatchEventKinds.ENTRY_DELETE) {
                            System.out.println(filename + " was successfully printed!");
                        }
                    }

                    //reset the key
                    boolean valid = key.reset();

                    //exit loop if the key is not valid
                    if (!valid) {
                        threads.clear();
                        break;
                    }
                }
                if (!threads.isEmpty()) {
                    for (Iterator<Map.Entry<Thread, Path>> it = threads.entrySet().iterator();
                         it.hasNext(); ) {
                        Map.Entry<Thread, Path> entry = it.next();
                        if (entry.getKey().getState() == Thread.State.TERMINATED) {
                            Files.deleteIfExists(entry.getValue());
                            it.remove();
                        }
                    }
                }
            }
        }
    }

    public static void main(String[] args) {
        final Path path = Paths.get("C:/printertray");
        WatchPrinterTray watch = new WatchPrinterTray();
        try {
            watch.watchTray(path);
        } catch (IOException | InterruptedException ex) {
            System.err.println(ex);
        }
    }
}

class Print implements Runnable {
    private Path doc;

    Print(Path doc) {
        this.doc = doc;
    }

    @Override
    public void run() {
        try {
            //sleep a random number of seconds for simulating dispatching and printing
            Thread.sleep(20000 + new Random().nextInt(30000));
            System.out.println("Printing: " + doc);
        } catch (InterruptedException ex) {
            System.err.println(ex);
        }
    }
}

  • 7 随机存取文件
Java 7提供SeekableByteChannel用于随机存取文件。
  • 7.1 ByteBuffer简介
ByteBuffer属性: 0 ≤ mark ≤ position ≤ limit ≤ capacity
ByteBuffer的方法:
http://download.oracle.com/javase/7/docs/api/index.html
http://download.oracle.com/javase/7/docs/index.html.

public abstract byte get()
public ByteBuffer get(byte[] dst)
public ByteBuffer get(byte[] dst, int offset, int length)
public abstract byte get(int index)
public abstract ByteBuffer put(byte b)
public final ByteBuffer put(byte[] src)
public ByteBuffer put(byte[] src, int offset, int length)
public ByteBuffer put(ByteBuffer src)
public abstract ByteBuffer put(int index, byte b)
public abstract char getChar()
public abstract char getChar(int index)
public abstract double getDouble()
public abstract double getDouble(int index)
public abstract float getFloat()
public abstract float getFloat(int index)
public abstract int getInt()
public abstract int getInt(int index)
public abstract long getLong()
public abstract long getLong(int index)
public abstract short getShort()
public abstract short getShort(int index)
public abstract ByteBuffer putChar(char value)
public abstract ByteBuffer putChar(int index, char value)
public abstract ByteBuffer putDouble(double value)
public abstract ByteBuffer putDouble(int index, double value)
public abstract ByteBuffer putFloat(float value)
public abstract ByteBuffer putFloat(int index, float value)
public abstract ByteBuffer putInt(int value)
public abstract ByteBuffer putInt(int index, int value)
public abstract ByteBuffer putLong(int index, long value)
public abstract ByteBuffer putLong(long value)
public abstract ByteBuffer putShort(int index, short value)
public abstract ByteBuffer putShort(short value)
  • 7.2Channels简介
Channels are analogous to streams, but with a few differences:
•  While streams are typically one-way (read or write), channels support read and write.
•  Channels can be read and written asynchronously.
•  Channels always read to, or write from, a buffer. All data that is sent to a channel must first be placed in a buffer. Any data that is read from a channel is read into a  buffer.
  • 7.3 使用SeekableByteChannel
StandardOpenOption属性
READ  Opens file for read access
WRITE Opens file for write access 
CREATE  Creates a new file if it does not exist
CREATE_NEW  Creates a new file, failing with an exception if the file already exists
APPPEND  Appends data to the end of the file (used with WRITE and CREATE)
DELETE_ON_CLOSE  Deletes the file when the stream is closed (used for deleting temporary files)
TRUNCATE_EXISTING  Truncates the file to 0 bytes (used with the WRITE option)
SPARSE  Causes the newly created file to be sparse
SYNC  Keeps the file content and metadata synchronized with the underlying storage device
DSYNC  Keeps the file content synchronized with the underlying storage device

(1)使用SeekableByteChannel读取文件
package com.eshore.raf;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

/**
* Created by ad on 2015/3/20.
*/
public class Main {
    public static void main(String[] args) {
        Path path = Paths.get("C:/", "racquet.txt");

          //read a file using SeekableByteChannel
        try (SeekableByteChannel seekableByteChannel = Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.READ))) {
            ByteBuffer buffer = ByteBuffer.allocate(12);
            String encoding = System.getProperty("file.encoding");
            buffer.clear();
            while (seekableByteChannel.read(buffer) > 0) {
                buffer.flip();
                System.out.print(Charset.forName(encoding).decode(buffer));
                buffer.clear();
            }
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

(2)使用SeekableByteChannel写文件
package com.eshore.raf;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

/**
* Created by ad on 2015/3/20.
*/
public class SeekableByteChannelWriter {
    public static void main(String[] args) {


        Path path = Paths.get("C:/", "wiki.txt");
        //write a file using SeekableByteChannel
        try (
                SeekableByteChannel seekableByteChannel = Files.newByteChannel(path,
                        EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING))
        ) {
            ByteBuffer buffer = ByteBuffer.wrap("Rafa Nadal produced another masterclass of clay-court tennis to win his fifth French Open title...".getBytes());
            int write = seekableByteChannel.write(buffer);
            System.out.println("Number of written bytes: " + write);
            buffer.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

•  To write into a file that exists, at the beginning, use WRITE
•  To write into a file that exists, at the end, use WRITE and APPEND
•  To write into a file that exists and clean up its content before writing, use WRITE and TRUNCATE_EXISTING
•  To write into a file that does not exist, use CREATE (or CREATE_NEW) and WRITE

(3)SeekableByteChannel和文件属性

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.nio.file.attribute.FileAttribute;
import java.nio.file.attribute.PosixFilePermission;
import java.nio.file.attribute.PosixFilePermissions;
import java.util.EnumSet;
import java.util.Set;
public class Main {
     public static void main(String[] args) {

          Path path = Paths.get("home/rafaelnadal/email", "email.txt");
          ByteBuffer buffer = ByteBuffer.wrap("Hi Rafa, I want to congratulate you for the amazin match that you played ... ".getBytes());

          //create the custom permissions attribute for the email.txt file
          Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-r------");
          FileAttribute<Set<PosixFilePermission>> attr = PosixFilePermissions.asFileAttribute(perms);

          //write a file using SeekableByteChannel
          try (SeekableByteChannel seekableByteChannel = Files.newByteChannel(path,
                    EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.APPEND), attr)) {
                    int write = seekableByteChannel.write(buffer);
                    System.out.println("Number of written bytes: " + write);
          } catch (IOException ex) {
               System.err.println(ex);
          }
          buffer.clear();
     }
}

(4)使用旧的ReadableByteChannel接口 
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
public class Main {
     public static void main(String[] args) {
          Path path = Paths.get("C:/rafaelnadal/grandslam/RolandGarros", "story.txt");

          //read a file using ReadableByteChannel
          try (ReadableByteChannel readableByteChannel = Files.newByteChannel(path)) {

                    ByteBuffer buffer = ByteBuffer.allocate(12);
                    buffer.clear();
                    String encoding = System.getProperty("file.encoding");

                    while (readableByteChannel.read(buffer) > 0) {
                         buffer.flip();
                         System.out.print(Charset.forName(encoding).decode(buffer));
                         buffer.clear();
                    }
               } catch (IOException ex) {
                    System.err.println(ex);
               }
          }
}

(5)使用旧的WritableByteChannel接口

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

public class Main {
     public static void main(String[] args) {
          Path path = Paths.get("C:/rafaelnadal/grandslam/RolandGarros", "story.txt");

          //write a file using WritableByteChannel
          try (WritableByteChannel writableByteChannel = Files.newByteChannel(path,
               EnumSet.of(StandardOpenOption.WRITE, StandardOpenOption.APPEND))) {
               ByteBuffer buffer = ByteBuffer.wrap("Vamos Rafa!".getBytes());
               int write = writableByteChannel.write(buffer);
               System.out.println("Number of written bytes: " + write);
               buffer.clear();
          } catch (IOException ex) {
               System.err.println(ex);
          }
     }
}

(6)Playing with SeekableByteChannel Position

Example 1: Read One Character from Different Positions
package com.eshore.raf;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
/**
* Created by ad on 2015/3/20.
*/
public class Main1 {
    public static void main(String[] args) {
        Path path = Paths.get("C:/", "wiki.txt");
        ByteBuffer buffer = ByteBuffer.allocate(1);
        String encoding = System.getProperty("file.encoding");

        try (SeekableByteChannel seekableByteChannel = (Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.READ)))) {

            //the initial position should be 0 anyway
            seekableByteChannel.position(0);
            System.out.println("Reading one character from position: " +
                    seekableByteChannel.position());
            seekableByteChannel.read(buffer);
            buffer.flip();
            System.out.print(Charset.forName(encoding).decode(buffer));
            buffer.rewind();

            //get into the middle
            seekableByteChannel.position(seekableByteChannel.size()/2);
            System.out.println("\nReading one character from position: " +
                    seekableByteChannel.position());
            seekableByteChannel.read(buffer);
            buffer.flip();
            System.out.print(Charset.forName(encoding).decode(buffer));
            buffer.rewind();

            //get to the end
            seekableByteChannel.position(seekableByteChannel.size()-1);
            System.out.println("\nReading one character from position: " +
                    seekableByteChannel.position());
            seekableByteChannel.read(buffer);
            buffer.flip();
            System.out.print(Charset.forName(encoding).decode(buffer));
            buffer.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

Reading one character from position: 0
R
Reading one character from position: 98
R
Reading one character from position: 195
.

Example 2: Write Characters at Different Positions
package com.eshore.raf;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
/**
* Created by ad on 2015/3/20.
*/
public class Main2 {
    public static void main(String[] args) {
        Path path = Paths.get("C:/", "wiki.txt");
        ByteBuffer buffer_1 = ByteBuffer.wrap("Great players participate in our tournament, like: Tommy Robredo, Fernando Gonzalez, Jose Acasuso or Thomaz Bellucci.".getBytes());
        ByteBuffer buffer_2 = ByteBuffer.wrap("Gonzalez".getBytes());

        try (SeekableByteChannel seekableByteChannel = (Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.WRITE)))) {
            //append some text at the end
            seekableByteChannel.position(seekableByteChannel.size());
            while (buffer_1.hasRemaining()) {
                seekableByteChannel.write(buffer_1);
            }

            //replace "Gonsales" with "Gonzalez"
            seekableByteChannel.position(301);
            while (buffer_2.hasRemaining()) {
                seekableByteChannel.write(buffer_2);
            }
            buffer_1.clear();
            buffer_2.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

Example 3: Copy a Portion of a File from the Beginning to the End
package com.eshore.raf;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
/**
* Created by ad on 2015/3/20.
*/
public class Main3 {
    public static void main(String[] args) {
        Path path = Paths.get("C:/", "wiki.txt");
        ByteBuffer copy = ByteBuffer.allocate(25);
        copy.put("\r".getBytes());
        try (SeekableByteChannel seekableByteChannel = (Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))) {

            int nbytes;
            do {
                nbytes = seekableByteChannel.read(copy);
            } while (nbytes != -1 && copy.hasRemaining());

            copy.flip();
            seekableByteChannel.position(seekableByteChannel.size());
            while (copy.hasRemaining()) {
                seekableByteChannel.write(copy);
            }
            copy.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

Example 4: Replace a File Portion with Truncate Capability
package com.eshore.raf;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
/**
* Created by ad on 2015/3/20.
*/
public class Main4 {
    public static void main(String[] args) {

        Path path = Paths.get("C:/", "wiki.txt");

        ByteBuffer buffer = ByteBuffer.wrap("The tournament has taken a lead in environmental  conservation efforts, with highlights including the planting of 500 trees to neutralise carbo emissions and providing recyclable materials to local children for use in craft work.".getBytes());

        try (SeekableByteChannel seekableByteChannel = (Files.newByteChannel(path,
                EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))) {

            seekableByteChannel.truncate(20);
            seekableByteChannel.position(seekableByteChannel.size()-1);
            while (buffer.hasRemaining()) {
                seekableByteChannel.write(buffer);
            }
            buffer.clear();
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}

  • 7.4 使用FileChannel
Path path = Paths.get("…");

try (FileChannel fileChannel = (FileChannel.open(path, EnumSet.of(
          StandardOpenOption.READ, StandardOpenOption.WRITE)))) {

} catch (IOException ex) {
     System.err.println(ex);
}
或者
try (FileChannel fileChannel = (FileChannel)(Files.newByteChannel(path,
          EnumSet.of(StandardOpenOption.READ, StandardOpenOption.WRITE)))){

} catch (IOException ex) {
     System.err.println(ex);
}
  • 7.4.1 文件直接映射内存
map方法有3个参数:
•   mode: Mapping a region into memory can be accomplished in one of three modes:  MapMode.READ_ONLY(read-only mapping; writing attempts will throw ReadOnlyBufferException),  MapMode.READ_WRITE (read/write mapping; changes in the resulting buffer can be propagated to the file and can be visible from other programs that map the same file), or  MapMode.PRIVATE (copy-on-write mapping; changes in the resulting buffer can’t be propagated to the file and aren’t visible from other programs).
•   position: The mapped region starts at the indicated position within the file (non-negative).
•   size: Indicates the size of the mapped region (0 ≤ size ≤ Integer.MAX_VALUE).

package com.eshore.raf;

import java.io.IOException;
import java.nio.CharBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
/**
* Created by ad on 2015/3/20.
*/
public class Main5 {
    public static void main(String[] args) {

        Path path = Paths.get("C:/", "wiki.txt");
        MappedByteBuffer buffer = null;

        try (FileChannel fileChannel = (FileChannel.open(path,
                                      EnumSet.of(StandardOpenOption. READ)))) {

            buffer = fileChannel.map(FileChannel.MapMode. READ_ONLY, 0, fileChannel.size());
        } catch (IOException ex) {
            System.err.println(ex);
        }
        if (buffer != null) {
            try {
                Charset charset = Charset.defaultCharset();
                CharsetDecoder decoder = charset.newDecoder();
                CharBuffer charBuffer = decoder.decode(buffer);
                String content = charBuffer.toString();
                System.out.println(content);
                buffer.clear();
            } catch (CharacterCodingException ex) {
                System.err.println(ex);
            }
        }
    }
}
  Note  Only channels opened for reading can be mapped as read-only, and only channels opened for reading and writing can be mapped as read/write or private.
  • 7.4.2 锁Channel文件
Keep in mind the following:
•  “File locks are held on behalf of the entire Java virtual machine. They are not suitable for controlling access to a file by multiple threads within the same virtual machine.” (Java Platform SE 7 official documentation, http://download.oracle.com/javase/7/docs/api/java/nio/channels/FileLock.html.)
•  Windows takes care of locking directories and other structures for you, so a delete, rename, or write operation will fail if another process has the file open. Therefore, creating a Java lock over a system lock will fail.
•  The Linux kernel manages a set of functions known as advisory locking mechanisms. In addition, you can enforce locking at the kernel level with
mandatory locks. Therefore, when using Java locks, keep in mind this aspect.

package com.eshore.raf;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;

/**
* Created by ad on 2015/3/20.
*/
public class Main6 {
    public static void main(String[] args) {
        Path path = Paths.get("C:/", "wiki.txt");
        ByteBuffer buffer = ByteBuffer.wrap("Vamos Rafa!".getBytes());
        try (FileChannel fileChannel = (FileChannel.open(path, EnumSet.of(StandardOpenOption.READ,
                StandardOpenOption.WRITE)))) {

            // Use the file channel to create a lock on the file.
            // This method blocks until it can retrieve the lock.
            FileLock lock = fileChannel.lock();
            //  Try acquiring the lock without blocking. This method returns
            // null or throws an exception if the file is already locked.

            //try {
            // lock = fileChannel.tryLock();
            //} catch (OverlappingFileLockException e) {
            // File is already locked in this thread or virtual machine
            //}
            if (lock.isValid()) {
                System.out.println("Writing to a locked file ...");
                try {
                    Thread.sleep(60000);
                } catch (InterruptedException ex) {
                    System.err.println(ex);
                }
                fileChannel.position(0);
                fileChannel.write(buffer);
                try {
                    Thread.sleep(60000);
                } catch (InterruptedException ex) {
                    System.err.println(ex);
                }
            }
            // Release the lock
            lock.release();
            System.out.println("\nLock released!");
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }
}
  • 7.4.3 使用FileChannel复制文件
(1)Copying Files with FileChannel and a Direct or Non-direct ByteBuffer
final Path copy_from = Paths.get("C:/rafaelnadal/tournaments/2009/videos/Rafa Best Shots.mp4");
final Path copy_to = Paths.get("C:/Rafa Best Shots.mp4");
int bufferSizeKB = 4;
int bufferSize = bufferSizeKB * 1024;

System.out.println("Using FileChannel and direct buffer ...");
try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
               EnumSet.of(StandardOpenOption.READ)));
FileChannel fileChannel_to = (FileChannel.open(copy_to,
               EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
     // Allocate a direct ByteBuffer
     ByteBuffer bytebuffer = ByteBuffer.allocateDirect(bufferSize);
     // Read data from file into ByteBuffer
     int bytesCount;
     while ((bytesCount = fileChannel_from.read(bytebuffer)) > 0) {

          //flip the buffer which set the limit to current position, and position to 0
          bytebuffer.flip();

          //write data from ByteBuffer to file
          fileChannel_to.write(bytebuffer);

          //for the next read
          bytebuffer.clear();
     }
} catch (IOException ex) {
     System.err.println(ex);
}

To use a non-direct ByteBuffer, just replace the line
ByteBuffer bytebuffer = ByteBuffer.allocateDirect(bufferSize);
with the following line:
ByteBuffer bytebuffer = ByteBuffer.allocate(bufferSize);

(2)Copying Files with FileChannel.transferTo() or FileChannel.transferFrom()

System.out.println("Using FileChannel.transferTo method ...");
try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
          EnumSet.of(StandardOpenOption.READ)));
     FileChannel fileChannel_to = (FileChannel.open(copy_to,
          EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {

     fileChannel_from.transferTo(0L, fileChannel_from.size(), fileChannel_to);

    //fileChannel_to.transferFrom(fileChannel_from, 0L, (int) fileChannel_from.size());
} catch (IOException ex) {
     System.err.println(ex);


(3)Copying Files with FileChannel.map()

System.out.println("Using FileChannel.map method ...");
try (FileChannel fileChannel_from = (FileChannel.open(copy_from,EnumSet.of(StandardOpenOption.READ)));
     FileChannel fileChannel_to = (FileChannel.open(copy_to, EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
          MappedByteBuffer buffer = fileChannel_from. map(FileChannel.MapMode.READ_ONLY, 0,
          fileChannel_from.size());
          fileChannel_to.write(buffer);
          buffer.clear();
} catch (IOException ex) {
     System.err.println(ex);
}

(4)FileChannel复制方法测试
比较方法:
• FileChannel and a non-direct ByteBuffer
• FileChannel and a direct ByteBuffer
• FileChannel.transferTo()
• FileChannel.transferFrom()
• FileChannel.map()
• Using buffered streams and a byte array
• Using unbuffered streams and a byte array
• Files.copy() (Path to Path, InputStream to Path, and Path to OutputStream)

前置条件:
• Copied file type: MP4 video (the file is named Rafa Best Shots.mp4 and is initially located in C:\rafaelnadal\tournaments\2009\videos)
• Copied file size: 58.3MB
• Buffer size tested: 4KB, 16KB, 32KB, 64KB, 128KB, 256KB, and 1024KB
• Machine: Mobile AMD Sempron Processor 3400 + 1.80 GHz, 1.00GB RAM, 32-bit OS, Windows 7 Ultimate
• Measurement type: Using the System.nanoTime() method
•  Time was captured only after three ignored consecutive runs; the first three runs are ignored to achieve a trend. The first-time run is always slower than the subsequent runs.

package com.eshore.raf;
import java.nio.MappedByteBuffer;
import java.io.OutputStream;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
import static java.nio.file.LinkOption.NOFOLLOW_LINKS;
/**
* Created by ad on 2015/3/20.
*/
public class CopyTest {
    public static void deleteCopied(Path path) {
        try {
            Files.deleteIfExists(path);
        } catch (IOException ex) {
            System.err.println(ex);
        }
    }

    public static void main(String[] args) {
        final Path copy_from = Paths.get("C:/rafaelnadal/tournaments/2009/videos/Rafa Best Shots.mp4");
        final Path copy_to = Paths.get("C:/Rafa Best Shots.mp4");
        long startTime, elapsedTime;
        int bufferSizeKB = 4; //also tested for 16, 32, 64, 128, 256 and 1024
        int bufferSize = bufferSizeKB * 1024;
        deleteCopied(copy_to);

        //FileChannel and non-direct buffer
        System.out.println("Using FileChannel and non-direct buffer ...");
        try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
                EnumSet.of(StandardOpenOption.READ)));
             FileChannel fileChannel_to = (FileChannel.open(copy_to,
                     EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
            startTime = System.nanoTime();
            // Allocate a non-direct ByteBuffer
            ByteBuffer bytebuffer = ByteBuffer.allocate(bufferSize);
            // Read data from file into ByteBuffer
            int bytesCount;
            while ((bytesCount = fileChannel_from.read(bytebuffer)) > 0) {
                 //flip the buffer which set the limit to current position, and position to 0
                bytebuffer.flip();
                 //write data from ByteBuffer to file
                fileChannel_to.write(bytebuffer);
               //for the next read
                bytebuffer.clear();
            }
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);


      //FileChannel and direct buffer
        System.out.println("Using FileChannel and direct buffer ...");
        try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
                EnumSet.of(StandardOpenOption.READ)));
             FileChannel fileChannel_to = (FileChannel.open(copy_to,
                     EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
            startTime = System.nanoTime();
            // Allocate a direct ByteBuffer
            ByteBuffer bytebuffer = ByteBuffer.allocateDirect(bufferSize);
            // Read data from file into ByteBuffer
            int bytesCount;
            while ((bytesCount = fileChannel_from.read(bytebuffer)) > 0) {
                  //flip the buffer which set the limit to current position, and position to 0
                bytebuffer.flip();
                  //write data from ByteBuffer to file
                fileChannel_to.write(bytebuffer);
                  //for the next read
                bytebuffer.clear();
            }
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);

      //FileChannel.transferTo()
        System.out.println("Using FileChannel.transferTo method ...");
        try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
                EnumSet.of(StandardOpenOption.READ)));
             FileChannel fileChannel_to = (FileChannel.open(copy_to,
                     EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
            startTime = System.nanoTime();
            fileChannel_from.transferTo(0L, fileChannel_from.size(), fileChannel_to);
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);

        //FileChannel.transferFrom()
        System.out.println("Using FileChannel.transferFrom method ...");
        try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
                EnumSet.of(StandardOpenOption.READ)));
             FileChannel fileChannel_to = (FileChannel.open(copy_to,
                     EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
            startTime = System.nanoTime();
            fileChannel_to.transferFrom(fileChannel_from, 0L, (int) fileChannel_from.size());
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);

        //FileChannel.map
        System.out.println("Using FileChannel.map method ...");
        try (FileChannel fileChannel_from = (FileChannel.open(copy_from,
                EnumSet.of(StandardOpenOption.READ)));
             FileChannel fileChannel_to = (FileChannel.open(copy_to,
                     EnumSet.of(StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)))) {
            startTime = System.nanoTime();
            MappedByteBuffer buffer = fileChannel_from.map(FileChannel.MapMode.READ_ONLY,
                    0, fileChannel_from.size());
            fileChannel_to.write(buffer);
            buffer.clear();
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);

        //Buffered Stream I/O
        System.out.println("Using buffered streams and byte array ...");
        File inFileStr = copy_from.toFile();
        File outFileStr = copy_to.toFile();
        try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(inFileStr));
             BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(outFileStr))) {
            startTime = System.nanoTime();
            byte[] byteArray = new byte[bufferSize];
            int bytesCount;
            while ((bytesCount = in.read(byteArray)) != -1) {
                out.write(byteArray, 0, bytesCount);
            }
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);

        System.out.println("Using un-buffered streams and byte array ...");
        try (FileInputStream in = new FileInputStream(inFileStr);
             FileOutputStream out = new FileOutputStream(outFileStr)) {
            startTime = System.nanoTime();
            byte[] byteArray = new byte[bufferSize];
            int bytesCount;
            while ((bytesCount = in.read(byteArray)) != -1) {
                out.write(byteArray, 0, bytesCount);
            }
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException ex) {
            System.err.println(ex);
        }
        deleteCopied(copy_to);


        System.out.println("Using Files.copy (Path to Path) method ...");
        try {
            startTime = System.nanoTime();
            Files.copy(copy_from, copy_to, NOFOLLOW_LINKS);
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException e) {
            System.err.println(e);
        }
        deleteCopied(copy_to);

        System.out.println("Using Files.copy (InputStream to Path) ...");
        try (InputStream is = new FileInputStream(copy_from.toFile())) {
            startTime = System.nanoTime();
            Files.copy(is, copy_to);
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException e) {
            System.err.println(e);
        }
        deleteCopied(copy_to);

        System.out.println("Using Files.copy (Path to OutputStream) ...");
        try (OutputStream os = new FileOutputStream(copy_to.toFile())) {
            startTime = System.nanoTime();
            Files.copy(copy_from, os);
            elapsedTime = System.nanoTime() - startTime;
            System.out.println("Elapsed Time is " + (elapsedTime / 1000000000.0) + " seconds");
        } catch (IOException e) {
            System.err.println(e);
        }
    }
}
FileChannel and Non-direct Buffer vs. FileChannel and Direct Buffer

FileChannel.transferTo() vs. FileChannel.transferFrom() vs. FileChannel.map()

The three different Files.copy()approaches

FileChannel and Non-direct Buffer vs. FileChannel.transferTo() vs. Path to Path


  • 8 Socker  API
Nio.2引入了多播的实现MulticastChannel。

  • 8.1 NetworkChannel简介
NetworkChannel bind(SocketAddress local) throws IOException
SocketAddress getLocalAddress() throws IOException
  • 8.1.1 Socket选项
StandardSocketOptions类的枚举值:
枚举值说明
IP_MULTICAST_IFThis option is used to specify the network interface (NetworkInterface) used for multicast datagrams sent by the datagram-oriented socket; if it is null, then the OS will choose the outgoing interface (if one is available). By default, it is null, but the option’s value can be set after the socket is bound. When we talk about sending datagrams, you will see how to find out what
multicast interfaces are available on your machine.
IP_MULTICAST_LOOP This option’s value is a boolean that controls the loopback of multicast datagrams (this is OS dependent). You have to decide, as the application writer, whether you want the data you send to be looped back to your host or not. By default, this is TRUE, but the option’s value can be set after the socket is bound.
IP_MULTICAST_TTLThis option’s value is an integer between 0 and 255, and it represents the time-to-live for multicast packets sent out by the datagram-oriented socket. If not otherwise specified, multicast datagrams are sent with a default value of 1, to prevent them to be forwarded beyond the local network. With this option we can control the scope of the multicast datagrams. By default this is set to 1, but the option’s value can be set after the socket is bound.
IP_TOSThis option’s value is an integer representing the value of the Type of Service (ToS) octet in IP packets sent by sockets—the interpretation of this value is specific to the network. Currently this is available only for IPv4, and by default its
value is typically 0. The option’s value can be set any time after the socket is bound.
SO_BROADCASTThis option’s value it is a boolean that indicates if transmission of broadcast datagrams is allowed or not (specific to datagram-oriented sockets sending to IPv4 broadcast addresses). By default, it is FALSE, but the option’s value can be set any time.
SO_KEEPALIVEThis option’s value it is a boolean indicating if the connection should be kept alive or not. By default, it is set to FALSE, but the option’s value can be set any time.
SO_LINGERThis option’s value is an integer that represents a timeout in seconds (the linger interval). When attempting to close a blocking-mode socket via the close() method, it will wait for the duration of the linger interval before transmitting the unsent data (not defined for non-blocking mode). By default, it is a negative value, which means that this option is disabled. The option’s value can be set any time and the maximum value is OS dependent.
SO_RCVBUFThis option’s value is an integer that represents the size in bytes of the socket receive buffer—the input buffer used by the networking implementation. By default, the value is OS dependent, but it can be set before the socket is bound or
connected. Depending on the OS, the value can be changed after the socket is bound. Negative values are not allowed.
SO_SNDBUFThis option’s value is an integer that represents the size in bytes of the socket send buffer—the output buffer used by the networking implementation. By default, the value is OS dependent, but it can be set before the socket is bound or
connected. Depending on the OS, the value can be changed after the socket is bound. Negative values are not allowed.
SO_REUSEADDRThis option’s value is an integer that represents if an address can be reused or not. This is very useful in datagram multicasting when we want multiple programs to be bound to the same address. In the case of stream-oriented sockets,
the socket can be bound to an address when a previous connection is in the TIME_WAIT state – TIME_WAIT means the OS has received a request to close the socket, but waits for possible late communications from the client side. By default,
the option’s value is OS dependent, but it can be set before the socket is bound or connected.
TCP_NODELAYThis option’s value is an integer that enables/disables Nagle’s algorithm (for more information on Nagle’s algorithm, see
http://en.wikipedia.org/wiki/Nagle%27s_algorithm). By default it is FALSE, but it can be set at any time.

<T> T getOption(SocketOption<T> name) throws IOException
<T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOException
Set<SocketOption<?>> supportedOptions()

  • 8.2 TCP应用程序
  • 8.2.1 阻塞和非阻塞机制
  • 8.2.2阻塞TCP服务端
1 Creating a New Server Socket Channel

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

if (serverSocketChannel.isOpen()) {
     ...
}

2 Configuring Blocking Mechanisms

serverSocketChannel.configureBlocking(true);

3 Setting Server Socket Channel Options

serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
Set<SocketOption<?>> options = serverSocketChannel.supportedOptions();
for(SocketOption<?> option : options) System.out.println(option);

4 Binding the Server Socket Channel

final int DEFAULT_PORT = 5555;
final String IP = "127.0.0.1";
serverSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));

System.out.println(serverSocketChannel.getLocalAddress());

5 Accepting Connections

SocketChannel socketChannel = serverSocketChannel.accept();

System.out.println("Incoming connection from: " + socketChannel.getRemoteAddress()); //JDK7 NIO2 新增的方法

6 Transmitting Data over a Connection

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
...
while (socketChannel.read(buffer) != -1) {
     buffer.flip();
     socketChannel.write(buffer);
     if (buffer.hasRemaining()) {
               buffer.compact();
     } else {
               buffer.clear();
    }
}

使用流代替Buffer
InputStream in = socketChannel.socket().getInputStream();
OutputStream out = socketChannel.socket().getOutputStream();

关闭链接的I/O(NIO.2新增)
//shut down connection for reading
socketChannel.shutdownInput(); 

//shut down connection for writing
socketChannel.shutdownOutput();

boolean inputdown = socketChannel.socket().isInputShutdown();
boolean outputdown = socketChannel.socket().isOutputShutdown();

7 Closing the Channel

serverSocketChannel.close();
socketChannel.close();

8 Echo服务器
package com.eshore.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

/**
* Created by ad on 2015/3/23.
*/
public class TcpEchoServer {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
             Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();
            CharBuffer charBuffer;
            //create a new server socket channel
            try (ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {
                  //continue if it was successfully created
                  if (serverSocketChannel.isOpen()) {

                        //set the blocking mode
                        serverSocketChannel.configureBlocking(true);

                        //set some options
                        serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
                        serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);

                        //bind the server socket channel to local address
                        serverSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));

                        //display a waiting message while ... waiting clients
                        System.out.println("Waiting for connections ...");

                        //wait for incoming connections
                        while (true) {
                              try (SocketChannel socketChannel = serverSocketChannel.accept()) {
                                    System.out.println("Incoming connection from: " +
                                            socketChannel.getRemoteAddress());
                                    //transmitting data
                                    while (socketChannel.read(buffer) != -1) {
                                          buffer.flip();
                                          System.out.println(charBuffer.toString());
                                          socketChannel.write(ByteBuffer.wrap(charBuffer.toString().getBytes() ));
                                          if (buffer.hasRemaining()) {
                                                buffer.compact();
                                          } else {
                                                buffer.clear();
                                          }
                                    }
                              } catch (IOException ex) {
                              }
                        }
                  } else {
                        System.out.println("The server socket channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }

}

  • 8.2.3 阻塞TCP客户端
1 Creating a New Socket Channel

SocketChannel socketChannel = SocketChannel.open();
if (socketChannel.isOpen()) {
     ...
}

2 Configuring Blocking Mechanisms

socketChannel.configureBlocking(true);

3 Setting Socket Channel Options

socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024);
socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024);
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
socketChannel.setOption(StandardSocketOptions.SO_LINGER, 5);

Set<SocketOption<?>> options = socketChannel.supportedOptions();
for(SocketOption<?> option : options) System.out.println(option);

4 Connecting the Channel’s Socket

final int DEFAULT_PORT = 5555;
final String IP = "127.0.0.1";
socketChannel.connect(new InetSocketAddress(IP, DEFAULT_PORT));

if (socketChannel.isConnected()) {
     ...
}

5 Transmitting Data over a Connection

ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes());
ByteBuffer randomBuffer;
CharBuffer charBuffer;
Charset charset = Charset.defaultCharset();
CharsetDecoder decoder = charset.newDecoder();
...
socketChannel.write(helloBuffer);
while (socketChannel.read(buffer) != -1) {
buffer.flip();
charBuffer = decoder.decode(buffer);
System.out.println(charBuffer.toString());
if (buffer.hasRemaining()) {
buffer.compact();
} else {
buffer.clear();
}
int r = new Random().nextInt(100);
if (r == 50) {
System.out.println("50 was generated! Close the socket channel!");
break;
} else {
randomBuffer = ByteBuffer.wrap("Random number:"
.concat(String.valueOf(r)).getBytes());
socketChannel.write(randomBuffer);
}
}

6 Closing the Channel
 socketChannel.close();

7 Echo 客户端

package com.eshore.socket;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Random;

/**
* Created by ad on 2015/3/23.
*/
public class TcpEchoClient {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes());
            ByteBuffer randomBuffer;
            CharBuffer charBuffer;
            Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();

            //create a new socket channel
            try (SocketChannel socketChannel = SocketChannel.open()) {

                  //continue if it was successfully created
                  if (socketChannel.isOpen()) {

                        //set the blocking mode
                        socketChannel.configureBlocking(true);

                        //set some options
                        socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024);
                        socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024);
                        socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
                        socketChannel.setOption(StandardSocketOptions.SO_LINGER, 5);

                        //connect this channel's socket
                        socketChannel.connect(new InetSocketAddress(IP, DEFAULT_PORT));

                        //check if the connection was successfully accomplished
                        if (socketChannel.isConnected()) {

                              //transmitting data
                              socketChannel.write(helloBuffer);
                              while (socketChannel.read(buffer) != -1) {
                                    buffer.flip();
                                    charBuffer = decoder.decode(buffer);
                                    System.out.println(charBuffer.toString());
                                    if (buffer.hasRemaining()) {
                                          buffer.compact();
                                    } else {
                                          buffer.clear();
                                    }
                                    int r = new Random().nextInt(100);
                                    if (r == 50) {
                                          System.out.println("50 was generated! Close the socket channel!");
                                          break;
                                    } else {
                                          randomBuffer = ByteBuffer.wrap("Random number:".
                                                  concat(String.valueOf(r)).getBytes());
                                          socketChannel.write(randomBuffer);
                                    }
                              }
                        } else {
                              System.out.println("The connection cannot be established!");
                        }
                  } else {
                        System.out.println("The socket channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}

  • 8.2.4 测试
 服务端:
Waiting for connections ...
Incoming connection from: /127.0.0.1:51686
Hello !
Random number:26
Random number:21
Random number:47
。。。。 
Random number:59

客户端:
 
Hello !
Random number:26
Random number:21
Random number:47
 。。。。
Random number:59
50 was generated! Close the socket channel!

Process finished with exit code 0

  • 8.2.5 非阻塞的TCP/IP程序
 Selector was not modified in Java 7。

(1) 使用SelectionKey类
•  SelectionKey.OP_ACCEPT (acceptable): The associated client requests a connection (usually created on the server side for indicating that a client requires a connection).
•  SelectionKey.OP_CONNECT (connectable): The server accepts the connection (usually created on the client side).
•  SelectionKey.OP_READ (readable): This indicates a read operation.
•  SelectionKey.OP_WRITE (writable): This indicates a write operation.

维护了3个key的集合:
•  key-set: Contains the keys representing the current channel  registrations of this selector
  selected-key: Contains the set of keys such that each key’s channel was detected to be ready for at least one of the operations identified in the key’s interest set during a prior selection operation
•   cancelled-key: Contains the set of keys that have been cancelled but whose channels have not yet been deregistered。

Note All three sets are empty in a newly created selector.  Selectors are themselves safe for use by multiple concurrent threads, but their key sets however are not.

(2)使用Selector类的方法

•  Selector.open(): Creates a new selector.
•  Selector.select(): Selects a set of keys by performing a blocking selection operation.
•  Selector.select(t): Same as select, but the blocking is performed only for the specified milliseconds. If time expires and there is nothing to select, it returns 0.
•  Selector.selectNow(): Same as select, but with non-blocking selection operation. It returns 0 if there is nothing to select.
•  Selector.selectedKeys(): Returns this selector’s selected key set as Set<SelectionKey>.
•  Selector.keys(): Returns this selector’s key set as Set<SelectionKey>.
•  Selector.wakeup(): Causes the first selection operation that has not yet returned to return immediately.
•  SelectionKey.isValid(): Checks if the key is valid. A key is invalid if it is cancelled, its channel is closed, or its selector is closed.
•  SelectionKey.isReadable(): Tests whether this key’s channel is ready for reading.
•  SelectionKey.isWritable(): Tests whether this key’s channel is ready for writing.
•  SelectionKey.isAcceptable(): Tests whether this key’s channel is ready to accept a new socket connection.
•  SelectionKey.isConnectable(): Tests whether this key’s channel has either finished or failed to finish its socket connection operation.
•  SelectionKey.cancel(): Requests that the registration of this key’s channel with its selector be cancelled.
•  SelectionKey.interestOps(): Retrieves this key’s interest set.
•  SelectionKey.interestOps(t): Sets this key’s interest set to the given value.
•  SelectionKey.readyOps(): Retrieves this key’s ready-operation set.

(3)服务端

package com.eshore.socket;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* Created by ad on 2015/3/23.
*/
public class TcpNoBlockServer {

      private Map<SocketChannel, List<byte[]>> keepDataTrack = new HashMap<>();
      private ByteBuffer buffer = ByteBuffer.allocate(2 * 1024);

      private void startEchoServer() {

            final int DEFAULT_PORT = 5555;
            //open Selector and ServerSocketChannel by calling the open() method

            try (Selector selector = Selector.open();
                 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open()) {

                  //check that both of them were successfully opened
                  if ((serverSocketChannel.isOpen()) && (selector.isOpen())) {
                        //configure non-blocking mode
                        serverSocketChannel.configureBlocking(false);
                        //set some options
                        serverSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 256 * 1024);
                        serverSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                        //bind the server socket channel to port
                        serverSocketChannel.bind(new InetSocketAddress(DEFAULT_PORT));
                        //register the current channel with the given selector
                        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
                        //display a waiting message while ... waiting!
                        System.out.println("Waiting for connections ...");
                        while (true) {
                              //wait for incomming events
                              selector.select();
                              //there is something to process on selected keys
                              Iterator keys = selector.selectedKeys().iterator();
                              while (keys.hasNext()) {
                                    SelectionKey key = (SelectionKey) keys.next();
                                    //prevent the same key from coming up again
                                    keys.remove();
                                    if (!key.isValid()) {
                                          continue;
                                    }
                                    if (key.isAcceptable()) {
                                          acceptOP(key, selector);
                                    } else if (key.isReadable()) {
                                         readOP(key);
                                    } else if (key.isWritable()) {
                                          writeOP(key);
                                    }
                              }
                        }
                  } else {
                        System.out.println("The server socket channel or selector cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }

      //isAcceptable returned true
      private void acceptOP(SelectionKey key, Selector selector) throws IOException {
            ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
            SocketChannel socketChannel = serverChannel.accept();
            socketChannel.configureBlocking(false);
            System.out.println("Incoming connection from: " + socketChannel.getRemoteAddress());
           //write a welcome message
            socketChannel.write(ByteBuffer.wrap("Hello!\n".getBytes("UTF-8")));

            //register channel with selector for further I/O
            keepDataTrack.put(socketChannel, new ArrayList<byte[]>());
            socketChannel.register(selector, SelectionKey.OP_READ);
      }

      //isReadable returned true
      private void readOP(SelectionKey key) {
            try {
                  SocketChannel socketChannel = (SocketChannel) key.channel();
                  buffer.clear();
                  int numRead = -1;
                  try {
                        numRead = socketChannel.read(buffer);
                  } catch (IOException e) {
                        System.err.println("Cannot read error!");
                  }
                  if (numRead == -1) {
                        this.keepDataTrack.remove(socketChannel);
                        System.out.println("Connection closed by: " + socketChannel.getRemoteAddress());
                        socketChannel.close();
                        key.cancel();
                        return;
                  }
                  byte[] data = new byte[numRead];
                  System.arraycopy(buffer.array(), 0, data, 0, numRead);
                  System.out.println(new String(data, "UTF-8") + " from " +
                          socketChannel.getRemoteAddress());
                  // write back to client
                  doEchoJob(key, data);
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }

      //isWritable returned true
      private void writeOP(SelectionKey key) throws IOException {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            List<byte[]> channelData = keepDataTrack.get(socketChannel);
            Iterator<byte[]> its = channelData.iterator();
            while (its.hasNext()) {
                  byte[] it = its.next();
                  its.remove();
                  socketChannel.write(ByteBuffer.wrap(it));
            }
            key.interestOps(SelectionKey.OP_READ);
      }


      private void doEchoJob(SelectionKey key, byte[] data) {
            SocketChannel socketChannel = (SocketChannel) key.channel();
            List<byte[]> channelData = keepDataTrack.get(socketChannel);
            channelData.add(data);
            key.interestOps(SelectionKey.OP_WRITE);
      }

      public static void main(String[] args) {
            TcpNoBlockServer server = new TcpNoBlockServer();
            server.startEchoServer();
      }
}

(4)客户端

package com.eshore.socket;
import java.io.IOException;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;

/**
* Created by ad on 2015/3/23.
*/
public class TcpNoBlockClient {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            ByteBuffer buffer = ByteBuffer.allocateDirect(2 * 1024);
            ByteBuffer randomBuffer;
            CharBuffer charBuffer;
            Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();

            //open Selector and ServerSocketChannel by calling the open() method
            try (Selector selector = Selector.open();
                 SocketChannel socketChannel = SocketChannel.open()) {
                  //check that both of them were successfully opened
                  if ((socketChannel.isOpen()) && (selector.isOpen())) {
                        //configure non-blocking mode
                        socketChannel.configureBlocking(false);

                        //set some options
                        socketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024);
                        socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024);
                        socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);

                        //register the current channel with the given selector
                        socketChannel.register(selector, SelectionKey.OP_CONNECT);

                        //connect to remote host
                        socketChannel.connect(new java.net.InetSocketAddress(IP, DEFAULT_PORT));
                        System.out.println("Localhost: " + socketChannel.getLocalAddress());

                        //waiting for the connection
                        while (selector.select(1000) > 0) {

                              //get keys
                              Set keys = selector.selectedKeys();
                              Iterator its = keys.iterator();

                              //process each key
                              while (its.hasNext()) {
                                    SelectionKey key = (SelectionKey) its.next();

                                    //remove the current key
                                    its.remove();

                                    //get the socket channel for this key
                                    try (SocketChannel keySocketChannel=(SocketChannel) key.channel()) {

                                           //attempt a connection
                                          if (key.isConnectable()) {
                                                //signal connection success
                                                System.out.println("I am connected!");
                                                //close pending connections
                                                if (keySocketChannel.isConnectionPending()) {
                                                      keySocketChannel.finishConnect();
                                                }

                                                //read/write from/to server
                                                while (keySocketChannel.read(buffer) != -1) {
                                                      buffer.flip();
                                                      charBuffer = decoder.decode(buffer);
                                                      System.out.println(charBuffer.toString());
                                                      if (buffer.hasRemaining()) {
                                                            buffer.compact();
                                                      } else {
                                                            buffer.clear();
                                                      }
                                                      int r = new Random().nextInt(100);
                                                      if (r == 50) {
                                                            System.out.println("50 was generated! Close   the socket channel!");
                                                            break;
                                                      } else {
                                                            randomBuffer = ByteBuffer.wrap("Random number:"
                                                                    .concat(String.valueOf(r)).getBytes("UTF-8"));
                                                            keySocketChannel.write(randomBuffer);
                                                            try {
                                                                  Thread.sleep(1500);
                                                            } catch (InterruptedException ex) {
                                                            }
                                                      }
                                                }
                                          }
                                    } catch (IOException ex) {
                                          System.err.println(ex);
                                    }
                              }
                        }
                  } else {
                        System.out.println("The socket channel or selector cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}
  • 8.3 UDP应用程序
UDP特点:
(1) the packet sizes are limited to the amount that can be contained in a single IP packet—at most 65507 bytes; this is the 65535-byte IP packet size minus the minimum IP header of 20 bytes, and minus the 8-byte UDP header.
(2) each packet is an individual, and is handled separately (no packet is aware of other packets). Moreover, the packets can arrive in any order, and some of them can be lost without the sender being informed, or they can arrive faster or slower than they can be processed—there’s no guarantee of delivering/receiving data in a particular sequence and no guarantee that the delivered data will be received.
(3)Since the sender can’t track the packets’ routes, each packet encapsulates the remote IP address and the port. If TCP is like a telephone, UDP is like a letter.

  • 8.3.1 UDP服务端
1 Creating a Server Datagram–Oriented Socket Channel

使用java.nio.channels.DatagramChannel或者NIO.2 的DatagramChannel.open()方法。open方法需要java.net.ProtocolFamily协议簇参数,目前的实现有:
•   StandardProtocolFamily.INET: IP version 4 (IPv4)
•   StandardProtocolFamily.INET6: IP version 6 (IPv6)

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

The old NIO no-argument DatagramChannel.open() method is still available and can be used since it is not deprecated. But in this case, the ProtocolFamily of the channel’s socket is platform (configuration) dependent and therefore unspecified.
if (datagramChannel.isOpen()) {
     ...
}

2 Setting Datagram-Oriented Socket Channel Options

SO_REUSEADDR, SO_BROADCAST, IP_MULTICAST_LOOP, SO_SNDBUF, IP_MULTICAST_TTL, IP_TOS, IP_MULTICAST_IF, and SO_RCVBUF.
datagramChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
datagramChannel.setOption(StandardSocketOptions.SO_SNDBUF, 4 * 1024);

Set<SocketOption<?>> options = datagramChannel.supportedOptions();
for(SocketOption<?> option : options) System.out.println(option);

3 Binding the Datagram-Oriented Socket Channel

final int LOCAL_PORT = 5555;
final String LOCAL_IP = "127.0.0.1";
datagramChannel.bind(new InetSocketAddress(LOCAL_IP, LOCAL_PORT));

System.out.println(datagramChannel.getLocalAddress());

4 Transmitting Data Packets

DatagramChannel.send(): If this channel is in non-blocking mode and there is sufficient room in the underlying output buffer, or if this channel is in blocking mode and sufficient room becomes available, then the remaining bytes in the given buffer are transmitted as a single datagram to the given target address. This method may be invoked at any time. If another thread has already initiated a write operation upon this channel, however, then an invocation of this method will block until the first operation is complete. If this channel’s socket is not bound then this method will first cause the socket to be bound to an address that is assigned automatically, as if by invoking the bind() method with a parameter of null. 

DatagramChannel.receive(): If a datagram is immediately available, or if this channel is in blocking mode and one eventually becomes available, then the datagram is copied into the given byte buffer and its source address is returned. If this channel is in non-blocking mode and a datagram is not immediately available then this method immediately returns null. This method may be invoked at any time. If another thread has already initiated a read operation upon this channel, however, then an invocation of this method will block until the first operation is complete. If this channel’s socket is not bound then this method will first cause the socket to be bound to an address that is assigned automatically, as if by invoking the bind() method with a parameter of null.

final int MAX_PACKET_SIZE = 65507;
ByteBuffer echoText = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);
...
while (true) {
SocketAddress clientAddress = datagramChannel.receive(echoText);
echoText.flip();
System.out.println("I have received " + echoText.limit() + " bytes from " + clientAddress.toString() + "! Sending them back ...");
datagramChannel.send(echoText, clientAddress);
echoText.clear();
}

5 Closing the Datagram Channel
datagramChannel.close();

6 服务端代码
package com.eshore.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;

/**
* Created by ad on 2015/3/23.
*/
public class UDPServer {
      public static void main(String[] args) {
            final int LOCAL_PORT = 5555;
            final String LOCAL_IP = "127.0.0.1"; //modify this to your local IP
            final int MAX_PACKET_SIZE = 65507;
            ByteBuffer echoText = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);
            //create a new datagram channel
            try (DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET)) {
                  //check if the channel was successfully opened
                  if (datagramChannel.isOpen()) {
                        System.out.println("Echo server was successfully opened!");
                        //set some options
                        datagramChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
                        datagramChannel.setOption(StandardSocketOptions.SO_SNDBUF, 4 * 1024);
                        //bind the channel to local address
                        datagramChannel.bind(new InetSocketAddress(LOCAL_IP, LOCAL_PORT));
                        System.out.println("Echo server was binded on:" + datagramChannel.getLocalAddress());
                        System.out.println("Echo server is ready to echo ...");
                        //transmitting data packets
                        while (true) {
                              SocketAddress clientAddress = datagramChannel.receive(echoText);
                              echoText.flip();
                              System.out.println("I have received " + echoText.limit() + " bytes from " +
                                      clientAddress.toString() + "! Sending them back ...");
                              datagramChannel.send(echoText, clientAddress);
                              echoText.clear();
                        }
                  } else {
                        System.out.println("The channel cannot be opened!");
                  }
            } catch (Exception ex) {
                  if (ex instanceof ClosedChannelException) {
                        System.err.println("The channel was unexpected closed ...");
                  }
                  if (ex instanceof SecurityException) {
                        System.err.println("A security exception occured ...");
                  }
                  if (ex instanceof IOException) {
                        System.err.println("An I/O error occured ...");
                  }
                  System.err.println("\n" + ex);
            }
      }
}

  • 8.3.2 无连接的UDP客户端
 If the server side is automatically bound (not explicitly), then the client should be aware of the chosen address (or more precisely, of the chosen IP address and port). The opposite is also true if the server sends the first data packet.

package com.eshore.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardProtocolFamily;
import java.nio.channels.DatagramChannel;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

/**
* Created by ad on 2015/3/23.
*/
public class UDPClient {
      public static void main(String[] args) throws IOException {
            final int REMOTE_PORT = 5555;
            final String REMOTE_IP = "127.0.0.1"; //modify this accordingly if you want to test remote
            final int MAX_PACKET_SIZE = 65507;
            CharBuffer charBuffer = null;
            Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();
            ByteBuffer textToEcho = ByteBuffer.wrap("Echo this: I'm a big and ugly server!".getBytes());
            ByteBuffer echoedText = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);
           
            //create a new datagram channel
            try (DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET)) {

                  //check if the channel was successfully opened
                  if (datagramChannel.isOpen()) {
                        //set some options
                        datagramChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
                        datagramChannel.setOption(StandardSocketOptions.SO_SNDBUF, 4 * 1024);

                        //transmitting data packets
                        int sent = datagramChannel.send(textToEcho,   new InetSocketAddress(REMOTE_IP, REMOTE_PORT));
                        System.out.println("I have successfully sent " + sent + " bytes to the Echo Server!");
                        datagramChannel.receive(echoedText);
                        echoedText.flip();
                        charBuffer = decoder.decode(echoedText);
                        System.out.println(charBuffer.toString());
                        echoedText.clear();
                  } else {
                        System.out.println("The channel cannot be opened!");
                  }
            } catch (Exception ex) {
                  if (ex instanceof ClosedChannelException) {
                        System.err.println("The channel was unexpected closed ...");
                  }
                  if (ex instanceof SecurityException) {
                        System.err.println("A security exception occured ...");
                  }
                  if (ex instanceof IOException) {
                        System.err.println("An I/O error occured ...");
                  }
                  System.err.println("\n" + ex);
            }
      }
}

  • 8.3.3 面向连接的UDP客户端
In a connected-client scenario, the channel’s socket is configured so that it only receives/sends datagrams from/to the given remote peer address. After the connection is established, data packets may not be received/sent from/to any other address. A datagram-oriented socket remains connected until it is  explicitly disconnected or until it is closed.

package com.eshore.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardProtocolFamily;
import java.nio.channels.DatagramChannel;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

/**
* Created by ad on 2015/3/23.
*/
public class UDPConnectedClient {
      public static void main(String[] args) throws IOException {
            final int REMOTE_PORT = 5555;
            final String REMOTE_IP = "127.0.0.1"; //modify this accordingly if you want to test remote
            final int MAX_PACKET_SIZE = 65507;
            CharBuffer charBuffer = null;
            Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();
            ByteBuffer textToEcho = ByteBuffer.wrap("Echo this: I'm a big and ugly server!".getBytes());
            ByteBuffer echoedText = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);
            //create a new datagram channel
            try (DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET)) {
                  //set some options
                  datagramChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
                  datagramChannel.setOption(StandardSocketOptions.SO_SNDBUF, 4 * 1024);

                  //check if the channel was successfully opened
                  if (datagramChannel.isOpen()) {
                         //connect to remote address
                        datagramChannel.connect(new InetSocketAddress(REMOTE_IP, REMOTE_PORT));


                        //check if the channel was successfully connected
                        if (datagramChannel.isConnected()) {

                              //transmitting data packets
                              int sent = datagramChannel.write(textToEcho);
                              System.out.println("I have successfully sent " + sent
                                      + " bytes to the Echo Server!");
                              datagramChannel.read(echoedText);
                              echoedText.flip();
                              charBuffer = decoder.decode(echoedText);
                              System.out.println(charBuffer.toString());
                              echoedText.clear();
                        } else {
                              System.out.println("The channel cannot be connected!");
                        }
                  } else {
                        System.out.println("The channel cannot be opened!");
                  }
            } catch (Exception ex) {
                  if (ex instanceof ClosedChannelException) {
                        System.err.println("The channel was unexpected closed ...");
                  }
                  if (ex instanceof SecurityException) {
                        System.err.println("A security exception occured ...");
                  }
                  if (ex instanceof IOException) {
                        System.err.println("An I/O error occured ...");
                  }
                  System.err.println("\n" + ex);
            }
      }
}
  • 8.3.4 多播
(1)MulticastChannel简介 

A group is identified by a class D IP address (a multicast group IPv4 address is between 224.0.0.1 and 239.255.255.255). When a new receiver (client) wants to join a multicast group, it needs to connect to the group through the corresponding IP address and listen for the incoming datagrams.

MembershipKey join(InetAddress g, NetworkInterface i) throws IOException

// we indicate a source address from which group members can begin receiving datagrams.
MembershipKey join(InetAddress g, NetworkInterface i, InetAddress s) throws IOException;

(2) MembershipKey简介

•   Block/unblock: You can block the sent datagrams from a specific source by calling the block() method and passing the source address. Moreover, you can unblock the blocked source by calling the unblock() method with the same address.
•   Get group: You can get the source address of the multicast group for which this membership key was created by calling the no-argument group() method. This method returns an InetAddress object.
  Get channel: You can get the channel for which this membership key was created by calling the no-argument method channel(). This method returns a MulticastChannel object.
•   Get source address: If the membership key is source specific (receives only datagrams from a specific source address), you can get the source address by calling the no-argument sourceAddress() method. This method returns an InetAddress object.
•   Get network interface: You can get the network interface for which this membership key was created by calling the no-argument networkInterface() method. This method returns a NetworkInterface object.
•   Check validity: You can check if a membership is valid by calling the isValid() method. This method returns a boolean value.
•   Drop: You can drop membership (the channel will no longer receive any datagrams sent to the group) by calling the no-argument drop() method.

(3)NetworkInterface简介
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Enumeration;

public class MainTest {
     public static void main(String argv[]) throws Exception {
          Enumeration enumInterfaces = NetworkInterface.getNetworkInterfaces();
          while (enumInterfaces.hasMoreElements()) {
               NetworkInterface net = (NetworkInterface) enumInterfaces.nextElement();
               System.out.println("Network Interface Display Name: " + net.getDisplayName());
               System.out.println(net.getDisplayName() + " is up and running ?" + net.isUp());
               System.out.println(net.getDisplayName()+" Supports Multicast: "+net.supportsMulticast());
               System.out.println(net.getDisplayName() + " Name: " + net.getName());
               System.out.println(net.getDisplayName() + " Is Virtual: " + net.isVirtual());
               System.out.println("IP addresses:");
               Enumeration enumIP = net.getInetAddresses();
               while (enumIP.hasMoreElements()) {
                    InetAddress ip = (InetAddress) enumIP.nextElement();
                    System.out.println("IP address:" + ip);
               }
     }
}
}

(4)UDP Multicast服务端
 package com.eshore.socket;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.nio.channels.DatagramChannel;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.util.Date;

/**
* Created by ad on 2015/3/23.
*/
public class MulticastServer {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String GROUP = "225.4.5.6";
            ByteBuffer datetime;

            //create a new channel
            try (DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET)) {
                  //check if the channel was successfully created
                  if (datagramChannel.isOpen()) {
                        //get the network interface used for multicast
                        NetworkInterface networkInterface = NetworkInterface.getByName("eth3");
                       
                        //set some options
                        datagramChannel.setOption(StandardSocketOptions.IP_MULTICAST_IF, networkInterface);
                        datagramChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                       
                        //bind the channel to the local address
                        datagramChannel.bind(new InetSocketAddress(DEFAULT_PORT));
                        System.out.println("Date-time server is ready ... shortly I'll start sending ...");
                       
                        //transmitting datagrams
                        while (true) {
                              //sleep for 10 seconds
                              try {
                                    Thread.sleep(10000);
                              } catch (InterruptedException ex) {
                              }
                              System.out.println("Sending data ...");
                              datetime = ByteBuffer.wrap(new Date().toString().getBytes());
                              datagramChannel.send(datetime, new
                                      InetSocketAddress(InetAddress.getByName(GROUP), DEFAULT_PORT));
                              datetime.flip();
                        }
                  } else {
                        System.out.println("The channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }

}

(5)UDP Multicast 客户端
package com.eshore.socket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.StandardProtocolFamily;
import java.nio.channels.DatagramChannel;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.MembershipKey;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

/**
* Created by ad on 2015/3/23.
*/
public class MulticastClient {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final int MAX_PACKET_SIZE = 65507;
            final String GROUP = "225.4.5.6";
            CharBuffer charBuffer = null;
            Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();
            ByteBuffer datetime = ByteBuffer.allocateDirect(MAX_PACKET_SIZE);

            //create a new channel
            try (DatagramChannel datagramChannel = DatagramChannel.open(StandardProtocolFamily.INET)) {
                  InetAddress group = InetAddress.getByName(GROUP);

                  //check if the group address is multicast
                  if (group.isMulticastAddress()) {
                        //check if the channel was successfully created
                        if (datagramChannel.isOpen()) {
                              //get the network interface used for multicast
                              NetworkInterface networkInterface = NetworkInterface.getByName("eth3");

                              //set some options
                              datagramChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);

                              //bind the channel to the local address
                              datagramChannel.bind(new InetSocketAddress(DEFAULT_PORT));

                              //join the multicast group and get ready to receive datagrams
                              MembershipKey key = datagramChannel.join(group, networkInterface);
                             
                              //wait for datagrams
                              while (true) {
                                    if (key.isValid()) {
                                          datagramChannel.receive(datetime);
                                          datetime.flip();
                                          charBuffer = decoder.decode(datetime);
                                          System.out.println(charBuffer.toString());
                                          datetime.clear();
                                    } else {
                                          break;
                                    }
                              }
                        } else {
                              System.out.println("The channel cannot be opened!");
                        }
                  } else {
                        System.out.println("This is not multicast address!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}

(6)Blocking and Unblocking Datagrams
      Sometimes joining multicast groups can bring to you undesired datagrams (the reasons are not relevant here). You can block receiving a datagram from a sender by calling the MembershipKey.block() method and passing to it the InetAddress of that sender. In addition, you can unblock the same sender, and start receiving datagrams from it again, by calling the MembershipKey.unblock() method and passing it the same InetAddress. Usually, you’ll be in one of the following two scenarios:

•  You have a list of senders’ addresses that you’d like to join. Supposing that the addresses are stored in a List, you can loop it and join each address separately, as shown here:

List<InetAddress> like = ...;
DatagramChannel datagramChannel =...;
if(!like.isEmpty()){
     for(InetAddress source: like){
          datagramChannel.join(group, network_interface, source);
     }
}

•  You have a list of senders’ addresses that you don’t want to join. Supposing that the addresses are stored in a List, then you can loop it and block each address separately, as shown here:

List<InetAddress> dislike = ...;
DatagramChannel datagramChannel =...;
MembershipKey key = datagramChannel.join(group, network_interface);

if(!dislike.isEmpty()){
     for(InetAddress source: dislike){
          key.block(source);
     }
}
  • 9异步Channel API
  • 9.1 同步I/O和异步I/O
  • 9.2 异步I/O总览
  • 9.2.1 Pending Result and the Future Class
java.util.concurrent.Future<V>
  • 9.2.2 Complete Result and the CompletionHandler Interface 
void completed(V result, A attachment)
void failed(Throwable exc, A attachment)
  • 9.2.3 Types of Asynchronous Channels
•  AsynchronousFileChannel
      不仅提供了读写操作功能,同时也提供了锁定文件、截断文件,或者文件大小的功能,不过不想同步的FileChannel,AsynchronousFileChannel 没有危害全局文件位置(即当前position)或者偏移量。即使没有有效的全局位置或者偏移量,每个读写操作都需要指定文件读写的位置。
       显式调用 close()关闭。
 
•  AsynchronousServerSocketChannel


•  AsynchronousSocketChannel

  • 9.2.4 Groups
       The asynchronous channel group encapsulates thread pool and the resources shared by all the threads working for the channels. Also, the channel is in effect owned by the group, so if the group is closed, the channel is closed too.
       Asynchronous channels are safe for use by multiple concurrent threads. Some channel implementations may support concurrent reading and writing but may not allow more than one read  and one write operation to be outstanding at any given time.

(1)默认组
通过下面两个参数设置:
java.nio.channels.DefaultThreadPool.threadFactory
java.nio.channels.DefaultThreadPool.initialSize

(2)自定义组
Fixed Thread Pool
      public static AsynchronousChannelGroup withFixedThreadPool(int nThreads, ThreadFactory threadFactory) throws IOException

Cached Thread Pool
      public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor, int initialSize) throws IOException

Designated Thread Pool
       public static AsynchronousChannelGroup withThreadPool(ExecutorService executor) throws IOException

Shutting Down a Group
       Calling the shutdown() method initiates the procedure of shutting down the group by marking the group as shutdown. Keep in mind that the shutdown() method will not force to stop or interrupt threads that are executing completion handlers.
     Note In the case of an asynchronous channel for stream-oriented connecting sockets, there is also the possibility to shut down the connection for reading by calling the  shutdownInupt() method (which will reject any further read attempts by returning the end-of-stream indicator,  -1 ) and for writing by calling the shutdownOutput() method (which will reject any writing attempts by throwing a  ClosedChannelException exception ) . Neither of these methods will close the channel.

  • 9.2.5 ByteBuffer注意事项
ByteBuffers是非线程安全的。可以考虑使用ByteBuffer池。

  • 9.2.6 ExecutorService API

class NetworkService implements Runnable {
   private final ServerSocket serverSocket;
   private final ExecutorService pool;

   public NetworkService(int port, int poolSize)
       throws IOException {
     serverSocket = new ServerSocket(port);
     pool = Executors.newFixedThreadPool(poolSize);
   }

   public void run() { // run the service
     try {
       for (;;) {
         pool.execute(new Handler(serverSocket.accept()));
       }
     } catch (IOException ex) {
       pool.shutdown();
     }
   }
 }

 class Handler implements Runnable {
   private final Socket socket;
   Handler(Socket socket) { this.socket = socket; }
   public void run() {
     // read and service request on socket
   }
 }

The following method shuts down an  ExecutorService in two phases, first by calling  shutdown to reject incoming tasks, and then calling  shutdownNow, if necessary, to cancel any lingering tasks: 

void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }
  • 9.3 开发异步应用
  • 9.3.1 Asynchronous File Channel例子
1 File Read和Future
package com.eshore.aio;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

/**
* Created by ad on 2015/3/24.
*/
public class AsynchronousFileChannelTest {
      public static void main(String[] args) {
            ByteBuffer buffer = ByteBuffer.allocate(100);
            String encoding = System.getProperty("file.encoding");
            Path path = Paths.get("C:/", "wiki.txt");
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.READ)) {
                  Future<Integer> result = asynchronousFileChannel.read(buffer, 0);
                  while (!result.isDone()) {
                        System.out.println("Do something else while reading ...");
                  }
                  System.out.println("Read done: " + result.isDone());
                  System.out.println("Bytes read: " + result.get());
            } catch (Exception ex) {
                  System.err.println(ex);
            }
            buffer.flip();
            System.out.print(Charset.forName(encoding).decode(buffer));
            buffer.clear();
      }
}

2 File Write and Future
package com.eshore.aio;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;
/**
* Created by ad on 2015/3/24.
*/
public class AsynchronousFileChannelTest {

      public static void main(String[] args) {
            ByteBuffer buffer = ByteBuffer.wrap("The win keeps Nadal at the top of the heap in men's tennis, at least for a few more weeks. The world No2, Novak Djokovic, dumped out here in the   semi-finals by a resurgent Federer, will come hard at them again at Wimbledon but there is  much to come from two rivals who, for seven years, have held all pretenders at bay.".getBytes());
            Path path = Paths.get("C:/", "wiki.txt");
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.WRITE)) {
                  Future<Integer> result = asynchronousFileChannel.write(buffer, 100);
                  while (!result.isDone()) {
                        System.out.println("Do something else while writing ...");
                  }
                  System.out.println("Written done: " + result.isDone());
                  System.out.println("Bytes written: " + result.get());
            } catch (Exception ex) {
                  System.err.println(ex);
            }
      }
}

3 File Read and Future Timeout

package com.eshore.aio;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Created by ad on 2015/3/24.
*/
public class AsynchronousFileChannelTest {

      public static void main(String[] args) {
            ByteBuffer buffer = ByteBuffer.allocate(100);
            int bytesRead = 0;
            Future<Integer> result = null;
            Path path = Paths.get("C:/", "wiki.txt");
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.READ)) {
                  result = asynchronousFileChannel.read(buffer, 0);
                  bytesRead = result.get(1, TimeUnit.NANOSECONDS);
                  if (result.isDone()) {
                        System.out.println("The result is available!");
                        System.out.println("Read bytes: " + bytesRead);
                  }
            } catch (Exception ex) {
                  if (ex instanceof TimeoutException) {
                        if (result != null) {
                              result.cancel(true);
                        }
                        System.out.println("The result is not available!");
                        System.out.println("The read task was cancelled ? " + result.isCancelled());
                        System.out.println("Read bytes: " + bytesRead);
                  } else {
                        System.err.println(ex);
                  }
            }
      }
}

4 File Read and CompletionHandler

package com.eshore.aio;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
* Created by ad on 2015/3/24.
*/
public class AsynchronousFileChannelTest {
      static Thread current;

      public static void main(String[] args) {
            ByteBuffer buffer = ByteBuffer.allocate(100);
            Path path = Paths.get("C:/", "wiki.txt");

            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.READ)) {
                  current = Thread.currentThread();
                  asynchronousFileChannel.read(buffer, 0, "Read operation status ...", new
                          CompletionHandler<Integer, Object>() {
                                @Override
                                public void completed(Integer result, Object attachment) {
                                      System.out.println(attachment);
                                      System.out.print("Read bytes: " + result);
                                      current.interrupt();
                                }

                                @Override
                                public void failed(Throwable exc, Object attachment) {
                                      System.out.println(attachment);
                                      System.out.println("Error:" + exc);
                                      current.interrupt();
                                }
                          });
                  System.out.println("\nWaiting for reading operation to end ...\n");
                  try {
                        current.join();
                  } catch (InterruptedException e) {
                  }
                  //now the buffer contains the read bytes
                  System.out.println("\n\nClose everything and leave! Bye, bye ...");
            } catch (Exception ex) {
                  System.err.println(ex);
            }
      }
}


package com.eshore.aio;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
* Created by ad on 2015/3/24.
*/
public class AsynchronousFileChannelTest {
      static Thread current;
      static final Path path = Paths.get("C:/", "wiki.txt");

      public static void main(String[] args) {

            Path path = Paths.get("C:/", "wiki.txt");
            CompletionHandler<Integer, ByteBuffer> handler =
                    new CompletionHandler<Integer, ByteBuffer>() {
                          String encoding = System.getProperty("file.encoding");

                          @Override
                          public void completed(Integer result, ByteBuffer attachment) {
                                System.out.println("Read bytes: " + result);
                                attachment.flip();
                                System.out.print(Charset.forName(encoding).decode(attachment));
                                attachment.clear();
                                current.interrupt();
                          }

                          @Override
                          public void failed(Throwable exc, ByteBuffer attachment) {
                                System.out.println(attachment);
                                System.out.println("Error:" + exc);
                                current.interrupt();
                          }
                    };
           
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.READ)) {
                  current = Thread.currentThread();
                  ByteBuffer buffer = ByteBuffer.allocate(100);
                  asynchronousFileChannel.read(buffer, 0, buffer, handler);
                  System.out.println("Waiting for reading operation to end ...\n");
                  try {
                        current.join();
                  } catch (InterruptedException e) {
                  }
                  //the buffer was passed as attachment
                  System.out.println("\n\nClosing everything and leave! Bye, bye ...");
            } catch (Exception ex) {
                  System.err.println(ex);
            }
      }
}

5 File Lock
package com.eshore.aio;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.Future;

/**
* Created by ad on 2015/3/24.
*/
public class FileLockTest {
      public static void main(String[] args) {
            ByteBuffer buffer = ByteBuffer.wrap("Argentines At Home In Buenos Aires Cathedral\n The Copa Claro is the third stop of the four-tournament Latin American swing, and is contested on  clay at the Buenos Aires Lawn Tennis Club, known as the Cathedral of Argentinean tennis. An   Argentine has reached the final in nine of the 11 editions of the ATP World Tour 250  tournament, with champions including Guillermo Coria, Gaston Gaudio, Juan Monaco and David   Nalbandian.".getBytes());
            Path path = Paths.get("C:/", "CopaClaro.txt");
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.CREATE, StandardOpenOption.WRITE)) {
                  Future<FileLock> featureLock = asynchronousFileChannel.lock();
                  System.out.println("Waiting for the file to be locked ...");
                  FileLock lock = featureLock.get();
                  //or, use shortcut
                  //FileLock lock = asynchronousFileChannel.lock().get();
                  if (lock.isValid()) {
                        Future<Integer> featureWrite = asynchronousFileChannel.write(buffer, 0);
                        System.out.println("Waiting for the bytes to be written ...");
                        int written = featureWrite.get();
                        //or, use shortcut
                        //int written = asynchronousFileChannel.write(buffer,0).get();
                        System.out.println("I’ve written " + written + " bytes into " +
                                path.getFileName() + " locked file!");
                        lock.release();
                  }
            } catch (Exception ex) {
                  System.err.println(ex);
            }
      }
}


package com.eshore.aio;

import java.io.IOException;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.channels.FileLock;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
* Created by ad on 2015/3/24.
*/
public class FileLockTest {
      static Thread current;

      public static void main(String[] args) {
            Path path = Paths.get("C:/", "CopaClaro.txt");
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    StandardOpenOption.READ, StandardOpenOption.WRITE)) {
                  current = Thread.currentThread();
                  asynchronousFileChannel.lock("Lock operation status:", new
                          CompletionHandler<FileLock, Object>() {
                                @Override
                                public void completed(FileLock result, Object attachment) {
                                      System.out.println(attachment + " " + result.isValid());
                                      if (result.isValid()) {
                                            //... processing ...
                                            System.out.println("Processing the locked file ...");
                                            //...
                                            try {
                                                  result.release();
                                            } catch (IOException ex) {
                                                  System.err.println(ex);
                                            }
                                      }
                                      current.interrupt();
                                }

                                @Override
                                public void failed(Throwable exc, Object attachment) {
                                      System.out.println(attachment);
                                      System.out.println("Error:" + exc);
                                      current.interrupt();
                                }
                          });
                  System.out.println("Waiting for file to be locked and process ... \n");
                  try {
                        current.join();
                  } catch (InterruptedException e) {
                  }
                  System.out.println("\n\nClosing everything and leave! Bye, bye ...");
            } catch (Exception ex) {
                  System.err.println(ex);
            }
      }
}

  Note  AsynchronousFileChannel also provides the well-known  tryLock() methods, but they are not associated with  Future or  CompletionHandler forms.

6 AsynchronousFileChannel and ExecutorService
package com.eshore.aio;

import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.*;

/**
* Created by ad on 2015/3/24.
*/
public class FileExecutorServiceTest {
      private static Set withOptions() {
            final Set options = new TreeSet<>();
            options.add(StandardOpenOption.READ);
            return options;
      }

      public static void main(String[] args) {
            final int THREADS = 5;
            ExecutorService taskExecutor = Executors.newFixedThreadPool(THREADS);
            String encoding = System.getProperty("file.encoding");
            List<Future<ByteBuffer>> list = new ArrayList<>();
            int sheeps = 0;
            Path path = Paths.get("C:/", "wiki.txt");
            try (AsynchronousFileChannel asynchronousFileChannel = AsynchronousFileChannel.open(path,
                    withOptions(), taskExecutor)) {
                  for (int i = 0; i < 50; i++) {
                        Callable<ByteBuffer> worker = new Callable<ByteBuffer>() {
                              @Override
                              public ByteBuffer call() throws Exception {
                                    ByteBuffer buffer = ByteBuffer.allocateDirect
                                            (ThreadLocalRandom.current().nextInt(100, 200));
                                    asynchronousFileChannel.read(buffer, ThreadLocalRandom.current().nextInt(0, 100));
                                    return buffer;
                              }
                        };
                        Future<ByteBuffer> future = taskExecutor.submit(worker);
                        list.add(future);
                  }
                  //this will make the executor accept no new threads
                  // and finish all existing threads in the queue
                  taskExecutor.shutdown();
                  //wait until all threads are finished
                  while (!taskExecutor.isTerminated()) {
                        //do something else while the buffers are prepared
                        System.out.println("Counting sheep while filling up some buffers  So far I counted: " + (sheeps += 1));
                  }
                  System.out.println("\nDone! Here are the buffers:\n");
                  for (Future<ByteBuffer> future : list) {
                        ByteBuffer buffer = future.get();
                        System.out.println("\n\n" + buffer);
                        System.out.println("______________________________________________________");
                        buffer.flip();
                        System.out.print(Charset.forName(encoding).decode(buffer));
                        buffer.clear();
                  }
            } catch (Exception ex) {
                  System.err.println(ex);
            }
      }
}

  • 9.3.2 Asynchronous Channel Sockets 例子
1 基于Future的异步服务端

package com.eshore.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
* Created by ad on 2015/3/25.
*/
public class EchoServer {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            //create an asynchronous server socket channel bound to the default group
            try (AsynchronousServerSocketChannel asynchronousServerSocketChannel =
                         AsynchronousServerSocketChannel.open()) {
                  if (asynchronousServerSocketChannel.isOpen()) {
                        //set some options
                        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
                        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                        //bind the asynchronous server socket channel to local address
                        asynchronousServerSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));
                        //display a waiting message while ... waiting clients
                        System.out.println("Waiting for connections ...");
                        while (true) {
                              Future<AsynchronousSocketChannel> asynchronousSocketChannelFuture =
                                      asynchronousServerSocketChannel.accept();
                              try (AsynchronousSocketChannel asynchronousSocketChannel =
                                           asynchronousSocketChannelFuture.get()) {
                                    System.out.println("Incoming connection from: " +
                                            asynchronousSocketChannel.getRemoteAddress());
                                    final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                                    //transmitting data
                                    while (asynchronousSocketChannel.read(buffer).get() != -1) {
                                          buffer.flip();
                                          asynchronousSocketChannel.write(buffer).get();
                                          if (buffer.hasRemaining()) {
                                                buffer.compact();
                                          } else {
                                                buffer.clear();
                                          }
                                    }
                                    System.out.println(asynchronousSocketChannel.getRemoteAddress() +
                                            " was successfully served!");
                              } catch (IOException | InterruptedException | ExecutionException ex) {
                                    System.err.println(ex);
                              }
                        }
                  } else {
                        System.out.println("The asynchronous server-socket channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}

package com.eshore.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.*;

/**
* Created by ad on 2015/3/25.
*/
public class EchoWithExecutorServer {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            ExecutorService taskExecutor =
                    Executors.newCachedThreadPool(Executors.defaultThreadFactory());

            //create asynchronous server socket channel bound to the default group
            try (AsynchronousServerSocketChannel asynchronousServerSocketChannel =
                         AsynchronousServerSocketChannel.open()) {
                  if (asynchronousServerSocketChannel.isOpen()) {
                        //set some options
                        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 4 * 1024);
                        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                        //bind the server socket channel to local address
                        asynchronousServerSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));
                        //display a waiting message while ... waiting clients
                        System.out.println("Waiting for connections ...");
                        while (true) {
                              Future<AsynchronousSocketChannel> asynchronousSocketChannelFuture =
                                      asynchronousServerSocketChannel.accept();
                              try {
                                    final AsynchronousSocketChannel asynchronousSocketChannel =
                                            asynchronousSocketChannelFuture.get();
                                    Callable<String> worker = new Callable<String>() {
                                          @Override
                                          public String call() throws Exception {
                                                String host = asynchronousSocketChannel.getRemoteAddress().toString();
                                                System.out.println("Incoming connection from: " + host);
                                                final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                                                //transmitting data
                                                while (asynchronousSocketChannel.read(buffer).get() != -1) {
                                                      buffer.flip();
                                                      asynchronousSocketChannel.write(buffer).get();
                                                      if (buffer.hasRemaining()) {
                                                            buffer.compact();
                                                      } else {
                                                            buffer.clear();
                                                      }
                                                }
                                                asynchronousSocketChannel.close();
                                                System.out.println(host + " was successfully served!");
                                                return host;
                                          }
                                    };
                                    taskExecutor.submit(worker);
                              } catch (InterruptedException | ExecutionException ex) {
                                    System.err.println(ex);
                                    System.err.println("\n Server is shutting down ...");
                                    //this will make the executor accept no new threads
                                    // and finish all existing threads in the queue
                                    taskExecutor.shutdown();
                                    //wait until all threads are finished
                                    while (!taskExecutor.isTerminated()) {
                                    }
                                    break;
                              }
                        }
                  } else {
                        System.out.println("The asynchronous server-socket channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}


2 基于Future的异步客户端
package com.eshore.aio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Random;
import java.util.concurrent.ExecutionException;

/**
* Created by ad on 2015/3/25.
*/
public class EchoClient {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
            ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes());
            ByteBuffer randomBuffer;
            CharBuffer charBuffer;
            Charset charset = Charset.defaultCharset();
            CharsetDecoder decoder = charset.newDecoder();
            //create an asynchronous socket channel bound to the default group
            try (AsynchronousSocketChannel asynchronousSocketChannel =
                         AsynchronousSocketChannel.open()) {
                  if (asynchronousSocketChannel.isOpen()) {
                        //set some options
                        asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024);
                        asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024);
                        asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
                        //connect this channel's socket
                        Void connect = asynchronousSocketChannel.connect
                                (new InetSocketAddress(IP, DEFAULT_PORT)).get();
                        if (connect == null) {
                              System.out.println("Local address: " +
                                      asynchronousSocketChannel.getLocalAddress());
                              //transmitting data
                              asynchronousSocketChannel.write(helloBuffer).get();
                              while (asynchronousSocketChannel.read(buffer).get() != -1) {
                                    buffer.flip();
                                    charBuffer = decoder.decode(buffer);
                                    System.out.println(charBuffer.toString());
                                    if (buffer.hasRemaining()) {
                                          buffer.compact();
                                    } else {
                                          buffer.clear();
                                    }
                                    int r = new Random().nextInt(100);
                                    if (r == 50) {
                                          System.out.println("50 was generated! Close the asynchronous socket channel !");
                                          break;
                                    } else {
                                          randomBuffer = ByteBuffer.wrap("Random number:".concat(String.valueOf(r)).getBytes());
                                          asynchronousSocketChannel.write(randomBuffer).get();
                                    }
                              }
                        } else {
                              System.out.println("The connection cannot be established!");
                        }
                  } else {
                        System.out.println("The asynchronous socket channel cannot be opened!");
                  }
            } catch (IOException | InterruptedException | ExecutionException ex) {
                  System.err.println(ex);
            }
      }
}


3 基于CompletionHandler的异步服务端

package com.eshore.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ExecutionException;
/**
* Created by ad on 2015/3/25.
*/
public class EchoWithCompletionHandlerServer {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            //create an asynchronous server socket channel bound to the default group
            try (AsynchronousServerSocketChannel asynchronousServerSocketChannel =
                         AsynchronousServerSocketChannel.open()) {
                  if (asynchronousServerSocketChannel.isOpen()) {
                        //set some options
                        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF,4 * 1024);
                        asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                        //bind the server socket channel to local address
                        asynchronousServerSocketChannel.bind(new InetSocketAddress(IP, DEFAULT_PORT));
                        //display a waiting message while ... waiting clients
                        System.out.println("Waiting for connections ...");
                        asynchronousServerSocketChannel.accept(null, new
                                CompletionHandler<AsynchronousSocketChannel, Void>() {
                                      final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                                      @Override
                                      public void completed(AsynchronousSocketChannel result, Void attachment) {
                                            asynchronousServerSocketChannel.accept(null, this);
                                            try {
                                                  System.out.println("Incoming connection from: " + result.getRemoteAddress());
                                                //transmitting data
                                                  while (result.read(buffer).get() != -1) {
                                                        buffer.flip();
                                                        result.write(buffer).get();
                                                        if (buffer.hasRemaining()) {
                                                              buffer.compact();
                                                        } else {
                                                              buffer.clear();
                                                        }
                                                  }
                                            } catch (IOException | InterruptedException | ExecutionException ex) {
                                                  System.err.println(ex);
                                            } finally {
                                                  try {
                                                        result.close();
                                                  } catch (IOException e) {
                                                        System.err.println(e);
                                                  }
                                            }
                                      }
                                      @Override
                                      public void failed(Throwable exc, Void attachment) {
                                            asynchronousServerSocketChannel.accept(null, this);
                                            throw new UnsupportedOperationException("Cannot accept connections!");
                                      }
                                });
                        // Wait
                        System.in.read();
                  } else {
                        System.out.println("The asynchronous server-socket channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}

4 基于CompletionHandler的异步客户端

package com.eshore.aio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.util.Random;
import java.util.concurrent.ExecutionException;
/**
* Created by ad on 2015/3/25.
*/
public class EchoWithCompletionHandlerClient {
      public static void main(String[] args) {
            final int DEFAULT_PORT = 5555;
            final String IP = "127.0.0.1";
            //create an asynchronous socket channel bound to the default group
            try (AsynchronousSocketChannel asynchronousSocketChannel =
                         AsynchronousSocketChannel.open()) {
                  if (asynchronousSocketChannel.isOpen()) {
                        //set some options
                        asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 128 * 1024);
                        asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 128 * 1024);
                        asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
                        //connect this channel's socket
                        asynchronousSocketChannel.connect(new InetSocketAddress(IP, DEFAULT_PORT), null,
                                new CompletionHandler<Void, Void>() {
                                      final ByteBuffer helloBuffer = ByteBuffer.wrap("Hello !".getBytes());
                                      final ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
                                      CharBuffer charBuffer = null;
                                      ByteBuffer randomBuffer;
                                      final Charset charset = Charset.defaultCharset();
                                      final CharsetDecoder decoder = charset.newDecoder();
                                      @Override
                                      public void completed(Void result, Void attachment) {
                                            try {
                                                  System.out.println("Successfully connected at: " +
                                                          asynchronousSocketChannel.getRemoteAddress());
                                                   //transmitting data
                                                  asynchronousSocketChannel.write(helloBuffer).get();
                                                  while (asynchronousSocketChannel.read(buffer).get() != -1) {
                                                        buffer.flip();
                                                        charBuffer = decoder.decode(buffer);
                                                        System.out.println(charBuffer.toString());
                                                        if (buffer.hasRemaining()) {
                                                              buffer.compact();
                                                        } else {
                                                              buffer.clear();
                                                        }
                                                        int r = new Random().nextInt(100);
                                                        if (r == 50) {
                                                              System.out.println("50 was generated! Close the asynchronous socket channel!");
                                                              break;
                                                        } else {
                                                              randomBuffer = ByteBuffer.wrap("Random  number:".concat(String.valueOf(r)).getBytes());
                                                              asynchronousSocketChannel.write(randomBuffer).get();
                                                        }
                                                  }
                                            } catch (IOException | InterruptedException | ExecutionException ex) {
                                                  System.err.println(ex);
                                            } finally {
                                                  try {
                                                        asynchronousSocketChannel.close();
                                                  } catch (IOException ex) {
                                                        System.err.println(ex);
                                                  }
                                            }
                                      }
                                      @Override
                                      public void failed(Throwable exc, Void attachment) {
                                            throw new UnsupportedOperationException("Connection cannot be established!");
                                      }
                                });
                        System.in.read();
                  } else {
                        System.out.println("The asynchronous socket channel cannot be opened!");
                  }
            } catch (IOException ex) {
                  System.err.println(ex);
            }
      }
}

5 Using Read/Write Operations and CompletionHandler

public abstract <A> void read(ByteBuffer[] dsts, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler<Long,? super A> handler);
public final <A> void read(ByteBuffer dst, A attachment, CompletionHandler<Integer,? super A> handler);
public abstract <A> void read(ByteBuffer dst,long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer,? super A> handler);
public abstract <A> void write(ByteBuffer[] srcs, int offset, int length, long timeout, TimeUnit unit, A attachment, CompletionHandler<Long,? super A> handler);
public final <A> void write(ByteBuffer src, A attachment, CompletionHandler<Integer,? super A> handler);
public abstract <A> void write(ByteBuffer src, long timeout, TimeUnit unit, A attachment, CompletionHandler<Integer,? super A> handler);

6 Writing an Asynchronous Client/Server Based on Custom Group

AsynchronousChannelGroup threadGroup = null;

ExecutorService executorService = Executors .newCachedThreadPool(Executors.defaultThreadFactory());
try {
     threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
} catch (IOException ex) {
     System.err.println(ex);
}
或者
AsynchronousChannelGroup threadGroup = null;

try {
     threadGroup = AsynchronousChannelGroup.withFixedThreadPool(5,     Executors.defaultThreadFactory());
} catch (IOException ex) {
     System.err.println(ex);
}

AsynchronousServerSocketChannel asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open(threadGroup);
AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open(threadGroup);

7 提示
以上代码只用于教学目的,生产环境可以参考下面的提示。

(1)使用Byte Buffer池和循环读操作
 In addition, there may be a danger here of running out of memory if your byte buffer grows too large, so you must be mindful of memory consumption (perhaps adjust Java heap parameters such as Xms and Xmx).

(2)Use Blocking Only for Short Reading Operations
For the next scenario, suppose that an  AsynchronousSocketChannel.read() method is reading from clients in Future mode, which means that the get() method will wait until the read operation completes, thus blocking the thread. In this scenario, you must make sure you do not lock your thread pool, especially if you are using a fixed thread pool. You can avoid this scenario by using blocking only for short reading operations. Using timeouts can also be a solution.

(3)Use FIFO-Q and Allow Blocking for Write Operations

Focusing now on write operations, consider the scenario in which an AsynchronousSocketChannel.write() method writes bytes to its client without blocking—it initiates the write operation and moves on to other tasks. But, moving on to other tasks may cause the thread to invoke the write() method again, and the completion handler has not yet been invoked by the previous write call. Bad idea! A WritePendingException exception will be thrown. You can fix this issue by making sure that the completion handler complete() method is invoked before a new write operation is initiated.
For this, use a first-in first out queue (FIFO-Q) for the byte buffers and write only when the previous write() has completed. So, use FIFO-Q and allow blocking for write operations.
Refer to the “ByteBuffers Considerations” section, earlier in this chapter, also.

8 AsynchronousDatagramChannel
JDK7中没未正式引入。 Java 7 DRAFT ea-b89的例子:
final AsynchronousDatagramChannel dc = AsynchronousDatagramChannel.open() .bind(new InetSocketAddress(4000));

// print the source address of all packets that we receive
dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() {
     public void completed(SocketAddress sa, ByteBuffer buffer) {
          System.out.println(sa);
          buffer.clear();
          dc.receive(buffer, buffer, this);
     }

     public void failed(Throwable exc, ByteBuffer buffer) {
          ...
     }
});
  • 10注意事项
  • 10.1 Refactoring java.io.File code
 java.io.File vs java.nio.file
Javadoc Description  java.io.File java.nio.File 
Class namejava.io.Filejava.nio.file.Path
Tests this abstract pathname for equality with the given objectFile.equals(Object)Path.equals(Object)
Compares two abstract pathnames lexicographicallyFile.compareTo(File)Path.compareTo(Path)
Returns the absolute pathname string of this abstract pathnameFile.getAbsolutePath() Path.toAbsolutePath()
Returns the absolute form of this abstract pathnameFile.getAbsoluteFile()Path.toAbsolutePath()
Returns the canonical pathname string of this abstract pathnameFile.getCanonicalPath()Path.toRealPath(LinkOption...)
Path.normalize()
Returns the canonical form of this abstract pathnameFile.getCanonicalFile()Path.toRealPath(LinkOption...)
Path.normalize()
Constructs a file: URI that represents this abstract pathnameFile.toURI()Path.toUri()
Tests whether the file denoted by this abstract pathname is a normal fileFile.isFile()Files.isRegularFile(Path, LinkOption ...)
Tests whether the file denoted by this abstract pathname is a directoryFile.isDirectory()Files.isDirectory(Path, LinkOption...)
Tests whether the file named by this abstract pathname is a hidden fileFile.isHidden() Files.isHidden(Path)
Tests whether the application can read the file denoted by this abstract pathnameFile.canRead() Files.isReadable(Path)
Tests whether the application can modify the file denoted by this  abstract pathnameFile.canWrite()Files.isWritable(Path)
Tests whether the application can execute the file denoted by this abstract pathnameFile.canExecute()  Files.isExecutable(Path)
Tests whether the file or directory denoted by this abstract pathname existsFile.exists()Files.exists(Path, LinkOption ...)
Files.notExists(Path,LinkOption ...)
Creates the directory named by this abstract pathnameFile.mkdir()Files.createDirectory(Path, FileAttribute<?> ...)
Creates the directory named by this abstract pathname, including any
necessary but nonexistent parent directories
File.mkdirs()Files.createDirectories(Path,
FileAttribute<?> ...)
创建不存在的文件File.createNewFile()Files.createFile(Path,
FileAttribute<?> ...)
Returns an array of strings naming the files and directories in the directory
denoted by this abstract pathname
File.list()
File.listFiles()
Files.newDirectoryStream(Path)
Returns an array of strings naming the files and directories in the directory
denoted by this abstract pathname that satisfy the specified filter
File.list(FilenameFilter)
File.listFiles(FileFilter)
File.listFiles(FilenameFilter)
Files.newDirectoryStream(Path,
DirectoryStream.Filter<? super Path>)
Files.newDirectoryStream(Path,String)
The length of the file denoted by this abstract pathnameFile.length()  Files.size(Path)
Deletes the file or directory denoted by this  abstract pathnameFile.delete()Files.delete(Path)
Files.deleteIfExists(Path)
Renames the file denoted by this abstract pathnameFile.renameTo(File)Files.move(Path, Path,
CopyOption)
Sets the owner or everybody’s execute permission for this abstract pathnameFile.setExecutable(boolean,
boolean)
Files.setAttribute(Path,
String, Object, LinkOption...)
Sets the owner or everybody’s read permission for this abstract pathnameFile.setReadable(boolean,
boolean)
Files.setAttribute(Path,
String, Object, LinkOption...)
Marks the file or directory named by this abstract pathname so that only
read operations are allowed
File.setReadOnly()Files.setAttribute(Path,
String, Object, LinkOption...)
Sets the owner or everybody’s write permission for this abstract pathnameFile.setWritable(boolean,
boolean)
Files.setAttribute(Path,
String, Object, LinkOption...)
Returns the time that the file denoted by this abstract pathname was
last modified
File.lastModified()Files.getLastModifiedTime(Path
path, LinkOption... options)
Sets the last-modified time of the file or directory named by this abstract
pathname
File.setLastModified(long)Files.setLastModifiedTime(Path,
FileTime)
Creates an empty file in the default temporary-file directory, using the given prefix and suffix to generate its nameFile.createTempFile(String,
String)
Files.createTempFile(String pre
fix, String suffix,
FileAttribute<?>... attrs)
Creates a new empty file in the specified directory, using the given prefix and suffix strings to generate its nameFile.createTempFile(String,
String, File)
Files.createTempFile(Path dir,
String prefix, String suffix,
FileAttribute<?>... attrs)
Returns the size of the partition named by this abstract pathnameFile.getTotalSpace()  FileStore.getTotalSpace()
Returns the number of unallocated bytes in the partition named by this
abstract path name
File.getFreeSpace() FileStore.getUnallocatedSpace()
Returns the number of bytes available to this virtual machine on the
partition named by this abstract pathname
File.getUsableSpace()FilesStore.getUsableSpace()
Lists the available file system rootsFile.listRoots()FileSystem.getRootDirectories()
Random access filejava.io.RandomAccessFilejava.nio.channels.SeekableByteChannel
Requests that the file or directory denoted by this abstract pathname be
deleted when the virtual machine terminates
File.deleteOnExit()Replaced by the DELETE_ON_CLOSE
option
Combines two pathsnew File(parent,"new_file") parent.resolve("new_file")

  • 10.2 Working with the ZIP file system provider
First, we create a simple HashMap that contains the configurable properties of a ZIP file system created by the ZFSP. Currently, there are two properties that can be configured:
•  create: The value can be true or false, but of type java.lang.String. If the value is true, the ZFSP creates a new ZIP file if it does not exist.
•  encoding: The value is a java.lang.String indicating the encoding scheme (e.g., UTF-8, US-ASCII, ISO-8859-1, etc.). UTF-8 is the default.

Therefore, we can indicate that the ZIP file exists and the needed encoding is ISO-8859-1 like so:
Map<String, String> env = new HashMap<>();
env.put("create", "false");
env.put("encoding", "ISO-8859-1");

URI uri = URI.create("jar:file:/C:/rafaelnadal/tournaments/2009/Tickets.zip");
FileSystem ZipFS = FileSystems.newFileSystem(uri, env);
public static FileSystem newFileSystem(Path path, ClassLoader loader) throws IOException
public static FileSystem newFileSystem(URI uri, Map<String,?> env, ClassLoader loader) throws IOException

package com.eshore.aio;

import java.io.IOException;
import java.net.URI;
import java.nio.file.*;
import java.util.HashMap;
import java.util.Map;

/**
* Created by ad on 2015/3/25.
*/
public class ZipSystemProviderTest {
      public static void main(String[] args) throws IOException {
            //set zip file system properties
            Map<String, String> env = new HashMap<>();
            env.put("create", "false");
            env.put("encoding", "ISO-8859-1");

            //locate file system with java.net.JarURLConnection
            URI uri = URI.create("jar:file:/C:/rafaelnadal/tournaments/2009/Tickets.zip");
            try (FileSystem ZipFS = FileSystems.newFileSystem(uri, env)) {
                  Path fileInZip = ZipFS.getPath("/AEGONTickets.png");
                  Path fileOutZip = Paths.get("C:/rafaelnadal/tournaments/2009/AEGONTicketsCopy.png");

                  //copy AEGONTickets.png outside the archive
                  Files.copy(fileInZip, fileOutZip);
                  System.out.println("The file was successfully copied!");
            }
      }
}

  • 10.3 Considerations about custom file system providers
Creating a Custom File System Provider 
1.  Extend the java.nio.file.spi.FileSystemProvider class.
2.  Define a URI scheme for the provider (the getScheme() method should return this URI scheme).
3.  Create an internal cache for managing the provider’s created file systems.
4.  Implement the newFileSystem() and getFileSystem() methods for creating a file system and for retrieving a reference to an existing file system.
5.  Implement the newFileChannel() or the newAsyncronousFileChannel() method, which returns a FileChannel object that allows a file to be read or written in the file system.

Creating a Custom File System  
1.  Extend the java.nio.file.FileSystem class.
2.  Implement the methods of the file system according to your needs (you may need to define the number of roots, read/write access, file stores, etc.).

For more details, you may want to take a closer look at official documentation, at  http://download.oracle.com/javase/7/docs/technotes/guides/io/fsp/filesystemprovider.html.

  • 10.4 Useful Methods
Default File System
You’ve seen how to get the default file system many times in this book, but we’re putting this so you can easily access this information if you forget. Getting the default file system is accomplished through the  FileSystems.getDefault() method:

FileSystem fs = FileSystems.getDefault();

File Stores
Getting the file system file stores is another well-covered subject in the book, but for a quick reminder, come here. Here’s the required code:

for (FileStore store: FileSystems.getDefault().getFileStores()) {
     ...
}

Path of a File
Here’s how to get the path of a file:

Path path = Paths.get("...");
Path path = FileSystems.getDefault().getPath("...");
Path path = Paths.get(URI.create("file:///..."));
Path path = Paths.get(System.getProperty("user.home"), "...");

Path String Separator
As you know, a path string separator is OS dependent. To retrieve the Path string separator for the default file system, you can use one of the following approaches:

String separator = File.separator;
String separator = FileSystems.getDefault().getSeparator();
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值