Paths
(1)什么是文件
[1]文件系统,在某种形式的介质(硬盘)上存储和组织文件,以便于检索
[2]目前,文件系统均以树形(或分层)结构存储文件
[3]树顶部是一个或多个根节点,在根节点下,有文件和目录
[4]每个目录可以包含文件和子目录,这些文件和子目录又可以包含文件和子目录等等
(可以达到几乎无限的深度[windows下文件全名有长度的限制])
(2)不同的操作系统
[1]linux中 :/home/sally/status
[2]windows中:c:\home\sally\status
[3]在windows文件系统也是可以使用"/"的,所以平时我们建议使用"/"反斜杠
(3)Absolute & Relative
[1]绝对路径:始终包含根元素和查找文件所需的完整目录列表
例如:D:/test/a.txt找到文件所需的所有信息都包含在路径声明中
[2]相对路径:没有更多信息,程序将没有办法进行访问
例如:a.txt 相对路径最终还是要基于绝对路径的描述
(4)File I/O
[1]java.io.File类,包含耦合了文件路径声明,以及文件操作方法的类;(不进行学习探讨)
[2NIO2(java8),将文件路径与文件操作,分离;且支持异步非阻塞
java.nio.file.Path接口,系统文件/目录的路径
java.nio.file.Files工具类,包含处理文件操作的方法,包括文件的创建,删除,复制,移动
(5)Interface Path
[1]Path接口,可以表示一个绝对的/相对的文件/目录的,路径
[2]Path代表一个不依赖于系统的文件路径(可以运行在不同的操作系统下)
[3]Path的具体实现在不同操作系统中不同,但开发者仅需面向Path描述路径,不用关心操作系统的差异
[4]Path仅用于描述路径,不包含对指定路径的操作方法
[5]相对路径不能以“/”开头
{1}/example/a.txt 描述的是绝对路径
{2}example/a.txt 描述的是相对路径
(6)创建一个Path
[1]java.nio.file.Paths工具类,通过转换路径字符串或URI来创建Path对象
{1}Paths类自动按系统的文件路径格式处理路径
{2}Path get(String path)
{3}Path get(Uri uri)
[2]Path.of(Sring path),基于Path接口中的静态方法创建Path对象(java 11)
{1}底层,自动基于当前运行的文件系统操作,实现文件与系统的解耦,
(相同的文件操作代码,可以运行在不同的系统上)
{2}原IO下的File类,无基于运行系统自动转换路径的实现方法
//实例分析
Path p1 = Paths.get("/tmp/foo");
Path p2 = Paths.get(args[0]);
Path p3 = Paths.get(URI.creat("file:///Users/joe/FileTest.java"));
(7)Path定义了许多获取文件数据信息的方法
[1]Path getFileName(),返回文件名或名称元素序列的最后一个元素
[2]Path getParent(),返回父目录的路径
[3]Path getRoot(), 返回路径的根
[4]实例分析
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
getPath();
}
private static void getPath() {
//创建的p就是Path对象
Path p = Path.of("D:/test/input.txt");
//获取实现类的名称
System.out.println(p.getClass().getName()); //输出:sun.nio.fs.WindowsPath
//正常直接打印p应该会输出一个地址,但是我们看到输出的是地址,所以代表类的内部重写了toString()方法
System.out.println(p); //输出:D:\test\input.txt
System.out.println(p.getFileName());
System.out.println(p.getParent());
System.out.println(p.getRoot());
}
}
[5]Path resolve(Path other)方法,将路径拼接成一个新路径
[6]Path Path.of(Strig.. more)方法,基于参数数组实现
例:Path path = Path.of("D:", "test", "input.txt");
[7]案例分析
{案例1}
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
getJoinPaths();
}
private static void getJoinPaths() {
Path dir = Path.of("D:/test");
Path file = Path.of("input.txt");
Path p1 = dir.resolve(file);
System.out.println(p1); //输出:D:/test/input.txt
Path p2 = Path.of("D:/test/input.txt");
System.out.println(p1.equals(p2)); //输出:true (Path重写了equals()方法)
Path p3 = Path.of("D:", "test", "input.txt");
System.out.println(p1.equals(p3)); //输出:true
//方法的路径拼接--无需手动添加目录的/正斜杠
}
}
{案例2}
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
getJoinPaths2();
}
private static void getJoinPaths2() {
Path base = Path.of("D:/test");
Path file = Path.of("input.txt");
System.out.println(base.toString()); //输出:D:/test
System.out.println(file.toString()); //输出:input.txt
//基于Path字符串拼接与基于resolve()方法路径拼接是完全不同的
System.out.println(base.toString()
+ file.toString()); //输出:D:/testinput.txt
System.out.println(base.resolve(file)); //输出:D:/test/input.txt
//自动为目录 + 文件路径的拼接(添加斜杠)
}
}
(8)File Operations
[1]java.nio.file.Files工具类,提供了丰富的静态方法,读取/写入/操作,文件与目录
[2]Files方法基于Path操作
{1}Checking a File or Directory
Boolean exists(Path pah) / notExists(Path path),path路径是否存在
Boolean isDirectory(Path path),path是否为目录
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
checkPath();
}
private static final Path BASE_PATH = Path.of("D:/test");
private static void checkPath() {
Path p = BASE_PATH.resolve("aaaaa");
System.out.println(Files.exists(p)); //输出:false
//判断p是否是一个目录
System.out.println("目录:" + Files.isDirectory(p)); //输出:目录:false
//判断BASE_PATH存不存在
System.out.println(Files.exists(BASE_PATH)); //输出:true
//判断BASE_PATH是不是一个目录
System.out.println("目录:" + Files.isDirectory(BASE_PATH)); //输出:目录:true
Path p2 = BASE_PATH.resolve("input.txt");
//判断input.txt文件是否存在
System.out.println(Files.exists(p2)); //输出:true
//判断input.txt是不是一个目录
System.out.println("目录:" + Files.isDirectory(p2)); //输出:false
}
}
{2}Creating a Directory
Path creatDirectory(Path dir) throws IOException
{目录已存在则异常,目录路径为多级目录,异常}
Path creatDirectories(Path dir) throws IOException
{自动创建多级不存在目录,目录即使存在也不会异常}
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
createDirectory();
}
private static void createDirectory() throws IOException {
Path dir = Path.of("D:/test/a/b/c");
//创建多级目录使用creatDirectories,会自动创建不存在的目录
Files.createDirectories(dir);
}
}
{3}Creating a Directory
Path creatFile(Path) throws IOException
{基于指定路径,创建文件,文件存在会产生异常}
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
createFile();
}
private static void createFile() throws IOException {
Path file = Path.of("D:/test/a/a.txt");
//创建a.txt的父目录
Files.createDirectories(file.getParent());
//根据指定的目录创建文件
Files.createFile(file);
}
}
{4}Copying a File or Directory
Path copy(Path source,Path target,CopyOption...options) throws IOException
{基于指定路径,创建文件,文件存在会产生异常}
java.nio.file.StandardCopyOption枚举,实现了CopyOption接口
注意:如果source为目录,不会复制里面的文件,仅相当于创建一个空目录
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
public class FilesTest {
public static void main(String[] args) throws IOException {
copy();
}
private static final Path BASE_PATH = Path.of("D:/test");
private static void copy() throws IOException {
Path source = BASE_PATH.resolve("input.txt");
Path target = BASE_PATH.resolve("output.txt");
//使用copy()两个参数的默认方法如果目标文件已经存在将会产生异常无法复制
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
//REPLACE_EXISTING 覆盖文件(如果存在相同的文件那么就会直接覆盖)
Files.copy(source, target, StandardCopyOption.ATOMIC_HOME);
//ATOMIC_HOME 将文件作为原子文件系统操作移动(多线程操作)
Files.copy(source, target, StandardCopyOption.COPY_ATTRIBUTES);
//COPY_ATTRIBUTES 将属性复制到新文件
}
}
{5}Moving a File or Directory
Path move(Path source,Path target,CopyOption...options) throws IOException
{将文件移动或者重命名为目标文件}
默认(如果目标文件存在,则异常),可通过options参数声明移动选项
如果在本目录下移动相当于文件改名
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
move();
}
private static final Path BASE_PATH = Path.of("D:/test");
private static void move() throws IOException {
Path source = BASE_PATH.resolve("input.txt");
Path target = BASE_PATH.resolve("output.txt");
Files.move(source,target)
//在相同的目录上进行移动相当于是改名
//也就是文件不变但是名字从input.txt改成output.txt
Path target1 = Path.of("D:/test2");
Files.move(BASE_PATH,target1);
//将目录改名
Path source2 = BASE_PATH.resolve("input.txt");
Path target2 = Path.of("D:/test/a/output.txt");
Files.createDirectories(target.getParent());
Files.move(source, target);
//不同目录,移动文件
}
}
{5}Deleting a File or Directory
void delete(Path path) throws IOException
{删除指定路径,路径不存在,异常}
boolean deleteIfExists(Path path) throws IOException
{路径不存在,不删除。返回是否删除成功}
注意:如果路径为目录,目录中包含文件(即不为空),上面两种删除均异常
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
delete();
}
private static final Path BASE_PATH = Path.of("D:/test");
private static void delete() throws IOException {
// 目录不为空,默认无法直接删除目录
Path dir = Path.of("D:/test");
Files.deleteIfExists(dir);
//文件不存在也不会产生异常,只是会返回一个false代表删除失败
Path path = BASE_PATH.resolve("input.txt");
Files.deleteIfExists(path);
//删除路径内有文件,所以无法删除
}
}
[3]walk
{1}Stream<Path> walk(Path start,int maxDepth) throws IOException
{2}Stream<Path> walk(Path start) throws IOException
{3}遍历,基于指定深度的遍历path路径中的文件
{4}避免了基于IO File的递归调用
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
walk();
}
private static final Path BASE_PATH = Path.of("D:/test");
private static void walk() throws IOException {
Path dir = Path.of("D:/test");
//循环遍历打印
Files.walk(dir).forEach(System.out::println);
System.out.println("---------");
//循环遍历打印,确定了深度为1层,到1层就不再向下遍历了
Files.walk(dir, 1).forEach(System.out::println);
}
}
(8)实例---在指定目录下,检索指定文件,全部删除
package com.experiment_3_IO;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class FilesTest {
public static void main(String[] args) throws IOException {
walk2();
}
private static final Path BASE_PATH = Path.of("D:/test");
private static void walk2() throws IOException {
Path file = Path.of("a.txt");
Files.walk(BASE_PATH)
.filter(p -> p.getFileName().equals(file))
.forEach(p -> {
try {
Files.delete(p);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}