Path 对象:表示一个文件或者目录的路径。父类 Paths
- Path.isAbsolute()
- Path.getFileName() // 获取文件名
- Path.getParent() // 除文件名其余路径
- Path.getRoot() // 获取根目录
- Path.toAbsolutePath();
- Path.toRealPath();
例:
Path p = Paths.get("C:", "path", "to", "nowhere", "NoFile.txt");ap = p.toAbsolutePath();rp = p.toRealPath();// 生成URIURI uri = p.toUri();// URI转为PathPath puri = Paths.get(uri);
*一定要注意:Path.toFile()转换为 File 对象, *
1.1 选取路径部分片段Path p = Paths.get("PartsOfPaths.java").toAbsolutePath();// 遍历打印每层路径,getName()索引Path的每一层,上限getNameCount()。for(int i = 0; i < p.getNameCount(); i++)System.out.println(p.getName(i));p.startsWith("/"); // truep.endWith("PartsOfPaths.java"); // truep.endWith(".java"); // false endWith比较的是完整路径。
Path 也实现了 Iterable 接口,因此可以通过增加行 for-each 进行遍历。
1.2 路径分析Path p = Paths.get("PathAnalysis.java").toAbsolutePath(); 常用分析 Path 相关方法 Files
- .exists(p) // 文件是否存在
- .isDirectory(p) // 是否是文件夹
- .isExecutable(p)
- .isReadable(p)
- .isWritable(p)
- .isHidden(p)
- .size(p)
- .getLastModifiedTime(p)
- .getOwner(p)
- Path.relativize() // 移除 Path 的根路径。
- Path.resolve() // 添加 Path 尾路径
- Path.getParent() // 删除 Path 尾路径
Files 包含大部分目录和文件操作方法。但没有删除目录树相关方法。
删除目录树方法:
publicstaticvoid rmdir(Path dir) throwsIOException{// 删除目录树的方法实现依赖于Files.walkFileTree(),即遍历每个子目录和文件// java.nio.file.SimpleFileVisitor提供了所有方法的默认实现Files.walkFileTree(dir, newSimpleFileVisitor<Path>() {@OverridepublicFileVisitResult visitFile(Path file, BasicFileAttributes attrs)throwsIOException{Files.delete(file);returnFileVisitResult.CONTINUE;}@OverridepublicFileVisitResult postVisitDirectory(Path dir, IOException exc)throwsIOException{Files.delete(dir);returnFileVisitResult.CONTINUE;}});}3 文件系统 FileSystem
FileSystem 为文件系统提供一个接口,是对象访问文件系统中文件和其他对象的工厂类。
FileSystem fsys = FileSystems.getDefaults(); // 默认文件系统for(FileStore fs : fsys.getFileStores()) show("File Store", fs);
文件系统是几种类型对象的工厂。
- getPath 路径字符串,返回一个 Path 对象,用于定位和访问文件
- getPathMatcher 创建一个 PathMatcher 对象在路径上执行匹配操作
- getFileStores 返回一个 FileStore 对象迭代器
- newWatchService 方法可用于监视对象进行更改事件
- getUserPrincipalLookupService 查找用户或组
1 作用:设置一个线程对目录的更改做出响应。
2 创建过程:
- 初始化:创建当前 OS 平台的文件监控对象 WatchService
- 注册:监控器注册到指定文件节点(只监控该节点的子节点,孙子节点不监控),开启监控线程来监控 Path.register(WatchService watcher, WatchEvent.Kind)
监控事件类型
- ENTRY_CREATE:创建
- ENTRY_DELETE:删除
- ENTRY_MODIFY:修改
- 获取监控池:监控池是静态的,只有主动获取监控池中信息才会更新(一般在文件发生变化后获取监控池变化后的信息)
- 重置监控器:WatchKey.reset();
获取监控信息:其实就是获取新的监控池
- WatchKey WatchService.poll(); // 尝试获取下一个变化信息的监控池,如果没有变化则返回 null
- WatchKey WatchService.take(); // 尝试获取下一个变化信息的监控池,如果没有变化则一直等待(长时间监控)
// 创建test文件夹 和 Hello.txt文件Path test = Paths.get("test");if(Files.exists(test))RmDir.rmdir(test);if(!Files.exists(test))Files.createDirectory(test);Files.createFile(test.resolve("Hello.txt"));// 从FileSystem中创建WatchService对象WatchService watcher = FileSystems.getDefault().newWatchService();// 注册到test节点以及操作类型test.register(watcher, ENTRY_DELETE);// delTxtFiles()方法用于删除.txt文件// 创建一个线程,设置运行前等待时间,删除.txtExecutors.newSingleThreadScheduledExecutor().schedule(PathWatcher::delTxtFiles, 250, TimeUnit.MILLISECONDS);// 获取监控池(保存事件列表) 一个文件变化动作可能会引发一系列的事件WatchKey key = watcher.take();for(WatchEvent evt : key.pollEvents()) {System.out.println("evt.context(): "+ evt.context() +"\nevt.count(): "+ evt.count() +"\nevt.kind(): "+ evt.kind());System.exit(0);}5 文件查询 PathMatcher
路径匹配器 模式:
- glob:通配符模式(功能有限,但够用)
- regex:正则模式
// 获取test路径节点Path test = Paths.get("test");// 以.tmp,.txt结尾的文件PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:**/*.{tmp,txt}");// 遍历文件下所有Files.walk(test).filter(matcher::matches).forEach(System.out::println);6 文件读取
先记录一下 IO 流方式读取文件
6.1 标准 IO :面向流特点:- 流是单向,只能读或者写
- 同步、阻塞
- 字节读写(InputStream/OutputStream)
- 字符读取(FileReader/FileWriter)
- 行读取(BufferedReader/BufferedWriter)
- 使用通道和缓冲区来操作流
- 通道是双向的,可写也可读
- 非阻塞,一个线程可处理多个读写
- 适用高并发、大量连接
- 效率高
- capacity:容量,缓冲区的大小
- limit:限制,表示最大的可读写的数量
- position:当前位置,每当读写,当前位置都会加一
- clear:将当前位置设置为 0,限制设置为容量,目的是尽最大可能让字节,由通道读取到缓冲中
- flip:当前位置置为限制,然后将当前位置置为 0,目的是将有数据部分的字节,由缓冲写入到通道中。通常用在读与写之间。
- 直接缓冲区方式:
- 通道之前直接传输:FileChannel.transferFrom() -> 效率差
- 内在映像文件传输:FileChannel.map() -> 效率中(老版存在内存泄漏,GC 会失败)
- 非直接缓冲区方式:Buffer 效率最高
- 创建输入输出流
File inf = newFile("in.txt");File outf = newFile("out.txt");FileInputStream inStream=newFileInputStream(inf);FileOutputStream outStream=newFileOutputStream(outf);
获取通道
FileChannel inChannel = inStream.getChannel();FileChannel outChannel = outStream.getChannel();
分配缓冲区大小
ByteBuffer buf = ByteBuffer.allocate(1024);// 三个属性:容量、位置、限制
通过缓冲区读写文件
buf.clear(); // 清空缓冲区while(inChannel.read(buf) != -1) { buf.flip();//缓冲区当前位置限制,然后将当前位置置0 outChanel.write(buf); buf.clear();}
关闭文件流
outChanel.close();inChannel.close();fileInputStream.close();fileOutputStream.close();6.3 NIO 包中方法
拥抱 java.nio.file.Files 和 java.nio.file.Paths
Files 主要操作 Paths:
- Files.copy
- FIles.move
- Files.deleteIfExists
- Files.createDirectory
- Files.readAllLines:一次性读取整个文件,生成一个字符串链表(小文件)
- Files.readAllBytes:一次性读取整个文件,字节数组(小文件)
- Files.lines:一行一行(大文件)
- Files.write
// 过滤注释行,每行只打印一半Files.readAllLines(Paths.get("test.java")).stream().filter(line -> !line.startsWith("//")).map(line -> line.substring(0, line.length() / 2)).forEach(System.out::println);
原作者:耿直小博
原文链接:java 编程思想 18 文件
原出处:公众号
侵删