一、文件I/O基石:Path
Java7中文件IO发生了很大的变化,专门引入了很多新的类来取代原来的基于java.io.File的文件IO操作方式:
import java.nio.file.DirectoryStream; import java.nio.file.FileSystem; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions;· ......等等
我们将从下面几个方面来学习Path类:
- 创建一个Path
- File和Path之间的转换,File和URI之间的转换
- 获取Path的相关信息
- 移除Path中的冗余项
1.1、创建一个Path
创建Path实例可以通过 Paths工具类 的 get()方法:
1 //使用绝对路径 2 Path path= Paths.get("c:\data\myfile.txt");
1 //使用相对路径 2 Path path = Paths.get("/home/jakobjenkov/myfile.txt");
下面这种创建方式和上面等效:
1 Path path = FileSystems.getDefault().getPath("c:\data\myfile.txt");
1.2、File和Path之间的转换,File和URI之间的转换
1 File file = new File("C:/my.ini"); 2 Path p1 = file.toPath(); 3 p1.toFile(); 4 file.toURI();
1.3、获取Path的相关信息
1 //使用Paths工具类的get()方法创建 2 Path path = Paths.get("D:\XMind\bcl-java.txt"); 3 /* //使用FileSystems工具类创建 4 Path path2 = FileSystems.getDefault().getPath("c:\data\myfile.txt");*/ 5 System.out.println("文件名:" + path.getFileName()); 6 System.out.println("名称元素的数量:" + path.getNameCount()); 7 System.out.println("父路径:" + path.getParent()); 8 System.out.println("根路径:" + path.getRoot()); 9 System.out.println("是否是绝对路径:" + path.isAbsolute()); 10 //startsWith()方法的参数既可以是字符串也可以是Path对象 11 System.out.println("是否是以为给定的路径D:开始:" + path.startsWith("D:\") ); 12 System.out.println("该路径的字符串形式:" + path.toString());
结果:
文件名:bcl-java.txt 名称元素的数量:2 父路径:D:XMind 根路径:D: 是否是绝对路径:true 是否是以为给定的路径D:开始:true 该路径的字符串形式:D:XMindcl-java.txt
1.4、移除冗余项
某些时候在我们需要处理的Path路径中可能会有一个或两个点
- .表示的是当前目录
- ..表示父目录或者说是上一级目录:
下面通过实例来演示一下使用Path类的normalize()和toRealPath()方法把.和..去除。
- normalize() : 返回一个路径,该路径是冗余名称元素的消除。
- toRealPath() : 融合了toAbsolutePath()方法和normalize()方法
1 //.表示的是当前目录 2 Path currentDir = Paths.get("."); 3 System.out.println(currentDir.toAbsolutePath());//输出C:UsersAdministratorNIODemo. 4 Path currentDir2 = Paths.get(".\NIODemo.iml"); 5 System.out.println("原始路径格式:"+currentDir2.toAbsolutePath()); 6 System.out.println("执行normalize()方法之后:"+currentDir2.toAbsolutePath().normalize()); 7 System.out.println("执行toRealPath()方法之后:"+currentDir2.toRealPath()); 8 9 //..表示父目录或者说是上一级目录: 10 Path currentDir3 = Paths.get(".."); 11 System.out.println("原始路径格式:"+currentDir3.toAbsolutePath()); 12 System.out.println("执行normalize()方法之后:"+currentDir3.toAbsolutePath().normalize()); 13 System.out.println("执行toRealPath()方法之后:"+currentDir3.toRealPath());
结果:
C:UsersAdministratorNIODemo.
原始路径格式:C:UsersAdministratorNIODemo.NIODemo.iml
执行normalize()方法之后:C:UsersAdministratorNIODemoNIODemo.iml
执行toRealPath()方法之后:C:UsersAdministratorNIODemoNIODemo.iml
原始路径格式:C:UsersAdministratorNIODemo..
执行normalize()方法之后:C:UsersAdministrator
执行toRealPath()方法之后:C:UsersAdministrator
二、Files工具类
Java NIO中的Files类(java.nio.file.Files)提供了多种操作文件系统中文件的方法。本节教程将覆盖大部分方法。Files类包含了很多方法,所以如果本文没有提到的你也可以直接查询JavaDoc文档。
java.nio.file.Files类是和java.nio.file.Path相结合使用的
2.1、检查给定的Path在文件系统中是否存在
通过 Files.exists() 检测文件路径是否存在:
1 Path path = Paths.get("D:\XMind\bcl-java.txt"); 2 3 boolean pathExists = Files.exists(path, new LinkOption[]{LinkOption.NOFOLLOW_LINKS}); 4 5 System.out.println(pathExists);//true
注意Files.exists()的的第二个参数。它是一个数组,这个参数直接影响到Files.exists()如何确定一个路径是否存在。在本例中,这个数组内包含了LinkOptions.NOFOLLOW_LINKS,表示检测时不包含符号链接文件。
2.2、创建文件/文件夹
- 创建文件:
通过 Files.createFile() 创建文件,
1 Path target2 = Paths.get("C:\mystuff.txt"); 2 try { 3 if(!Files.exists(target2)) 4 Files.createFile(target2); 5 } catch (IOException e) { 6 e.printStackTrace(); 7 }
-
创建文件夹:
- 通过 Files.createDirectory() 创建文件夹
- 通过 Files.createDirectories() 创建文件夹
Files.createDirectories()会首先创建所有不存在的父目录来创建目录,而Files.createDirectory()方法只是创建目录,如果它的上级目录不存在就会报错。比如下面的程序使用Files.createDirectory() 方法创建就会报错,这是因为我的D盘下没有data文件夹,加入存在data文件夹的话则没问题。
1 Path path = Paths.get("D://data//test"); 2 3 try { 4 Path newDir = Files.createDirectories(path); 5 } catch(FileAlreadyExistsException e){ 6 // the directory already exists. 7 } catch (IOException e) { 8 //something else went wrong 9 e.printStackTrace(); 10 }
2.3、删除文件或目录
通过 Files.delete()方法 可以删除一个文件或目录:
1 Path path = Paths.get("data/subdir/logging-moved.properties"); 2 3 try { 4 Files.delete(path); 5 } catch (IOException e) { 6 //deleting file failed 7 e.printStackTrace(); 8 }
2.4、把一个文件从一个地址复制到另一个位置
通过Files.copy()方法可以吧一个文件从一个地址复制到另一个位置
1 Path sourcePath = Paths.get("data/logging.properties"); 2 Path destinationPath = Paths.get("data/logging-copy.properties"); 3 4 try { 5 Files.copy(sourcePath, destinationPath); 6 } catch(FileAlreadyExistsException e) { 7 //destination file already exists 8 } catch (IOException e) { 9 //something else went wrong 10 e.printStackTrace(); 11 }
copy操作还可可以强制覆盖已经存在的目标文件,只需要将上面的copy()方法改为如下格式:
1 Files.copy(sourcePath, destinationPath, 2 StandardCopyOption.REPLACE_EXISTING);
2.5、获取文件属性
1 Path path = Paths.get("D:\XMind\bcl-java.txt"); 2 System.out.println(Files.getLastModifiedTime(path)); 3 System.out.println(Files.size(path)); 4 System.out.println(Files.isSymbolicLink(path)); 5 System.out.println(Files.isDirectory(path)); 6 System.out.println(Files.readAttributes(path, "*"));
结果:
1 2016-05-18T08:01:44Z 2 18934 3 false 4 false 5 {lastAccessTime=2017-04-12T01:42:21.149351Z, lastModifiedTime=2016-05-18T08:01:44Z, size=18934, creationTime=2017-04-12T01:42:21.149351Z, isSymbolicLink=false, isRegularFile=true, fil
2.6、遍历一个文件夹
1 Path dir = Paths.get("D:\Java"); 2 try(DirectoryStream<Path> stream = Files.newDirectoryStream(dir)){ 3 for(Path e : stream){ 4 System.out.println(e.getFileName()); 5 } 6 }catch(IOException e){ 7 8 }
结果:
apache-maven-3.5.0 Eclipse intellij idea Jar JDK MarvenRespository MyEclipse 2017 CI Nodejs RedisDesktopManager solr-7.2.1
上面是遍历单个目录,它不会遍历整个目录。遍历整个目录需要使用:Files.walkFileTree().Files.walkFileTree()方法具有递归遍历目录的功能
2.7、遍历整个文件目录:
walkFileTree接受一个Path和FileVisitor作为参数。Path对象是需要遍历的目录,FileVistor则会在每次遍历中被调用。
FileVisitor需要调用方自行实现,然后作为参数传入walkFileTree().FileVisitor的每个方法会在遍历过程中被调用多次。如果不需要处理每个方法,那么可以继承它的默认实现类SimpleFileVisitor,它将所有的接口做了空实现。
1 public class WorkFileTree { 2 3 public static void main(String[] args) throws IOException{ 4 Path startingDir = Paths.get("D:\apache-tomcat-9.0.0.M17"); 5 List<Path> result = new LinkedList<Path>(); 6 Files.walkFileTree(startingDir, new FindJavaVisitor(result)); 7 System.out.println("result.size()=" + result.size()); 8 } 9 10 private static class FindJavaVisitor extends SimpleFileVisitor<Path>{ 11 private List<Path> result; 12 public FindJavaVisitor(List<Path> result){ 13 this.result = result; 14 } 15 @Override 16 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs){ 17 if(file.toString().endsWith(".java")){ 18 result.add(file.getFileName()); 19 } 20 return FileVisitResult.CONTINUE; 21 } 22 } 23 }
上面这个例子输出了我的D:apache-tomcat-9.0.0.M17也就是我的Tomcat安装目录下以.java结尾文件的数量。
结果:
result.size()=4
Files类真的很强大,除了我讲的这些操作之外还有其他很多操作比如:读取和设置文件权限、更新文件所有者等等操作。
这里就介绍这么多了,如果想要详细了解的可以自行查阅官方文档或者相关书籍。
参考:https://www.cnblogs.com/snailclimb/p/9086333.html