0
点赞
收藏
分享

微信扫一扫

Java编程思想十八文件


1 文件和目录路径

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();
// 生成URI
URI uri = p.toUri();
// URI转为Path
Path 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("/"); // true
p.endWith("PartsOfPaths.java"); // true
p.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)

1.3 Paths 的修改

  • Path.relativize() // 移除 Path 的根路径。
  • Path.resolve() // 添加 Path 尾路径
  • Path.getParent() // 删除 Path 尾路径

2 目录

Files 包含大部分目录和文件操作方法。但没有删除目录树相关方法。

删除目录树方法:


publicstaticvoid rmdir(Path dir) throwsIOException{
// 删除目录树的方法实现依赖于Files.walkFileTree(),即遍历每个子目录和文件
// java.nio.file.SimpleFileVisitor提供了所有方法的默认实现
Files.walkFileTree(dir, newSimpleFileVisitor<Path>() {
@Override
publicFileVisitResult visitFile(Path file, BasicFileAttributes attrs)
throwsIOException{
Files.delete(file);
returnFileVisitResult.CONTINUE;
}

@Override
publicFileVisitResult 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 查找用户或组

4 路径监听 WatchService

1 作用:设置一个线程对目录的更改做出响应。

2 创建过程:

  1. 初始化:创建当前 OS 平台的文件监控对象 WatchService
  2. 注册:监控器注册到指定文件节点(只监控该节点的子节点,孙子节点不监控),开启监控线程来监控 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文件
// 创建一个线程,设置运行前等待时间,删除.txt
Executors.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)

6.2 NIO :面向缓冲、通道

特点:

  • 使用通道和缓冲区来操作流
  • 通道是双向的,可写也可读
  • 非阻塞,一个线程可处理多个读写
  • 适用高并发、大量连接
  • 效率高

缓冲区:一块有位置、界限、容量的内存。

  • capacity:容量,缓冲区的大小
  • limit:限制,表示最大的可读写的数量
  • position:当前位置,每当读写,当前位置都会加一

缓冲区常用方法:

  • clear:将当前位置设置为 0,限制设置为容量,目的是尽最大可能让字节,由通道读取到缓冲中
  • flip:当前位置置为限制,然后将当前位置置为 0,目的是将有数据部分的字节,由缓冲写入到通道中。通常用在读与写之间。

NIO 实现方式

  • 直接缓冲区方式:
  • 通道之前直接传输:FileChannel.transferFrom() -> 效率差
  • 内在映像文件传输:FileChannel.map() -> 效率中(老版存在内存泄漏,GC 会失败)
  • 非直接缓冲区方式:Buffer 效率最高

NIO 实现文件读写复制( 非直接缓冲区方式:效率最高)

  • 创建输入输出流

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编程思想十八文件_java


举报

相关推荐

0 条评论