1 文件监听简单使用
很多时候我们需要监听一个文件的变化或者目录的变动,包括文件的创建、修改、删除,以及目录下文件的创建、修改和删除
1.1 WatchMonitor
在Hutool中,WatchMonitor
主要针对JDK7中WatchService
做了封装,针对文件和目录的变动(创建、更新、删除)做一个钩子,在Watcher
中定义相应的逻辑来应对这些文件的变化。
1.2 内部应用
在hutool-setting模块,使用WatchMonitor监测配置文件变化,然后自动load到内存中。WatchMonitor的使用可以避免轮询,以事件响应的方式应对文件变化。
WatchMonitor
提供的事件有:
ENTRY_MODIFY
文件修改的事件ENTRY_CREATE
文件或目录创建的事件ENTRY_DELETE
文件或目录删除的事件OVERFLOW
丢失的事件
这些事件对应StandardWatchEventKinds
中的事件。
下面我们介绍WatchMonitor的使用:
1.3 监听指定事件
package com.oldlu.transfer.message.util; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.watch.SimpleWatcher; import cn.hutool.core.io.watch.WatchMonitor; import cn.hutool.core.io.watch.Watcher; import cn.hutool.core.lang.Console; import java.io.File; import java.nio.file.Path; import java.nio.file.WatchEvent; /** * @author oldlu * @version 1.0 * @date 2021/7/8 */ public class FileUtils { public static void main(String[] args) { File file2 = FileUtil.file("C:\\Users\\Administrator"); //这里只监听文件或目录的修改事件(可以根据要求修改) WatchMonitor watchMonitor = WatchMonitor.create(file2, WatchMonitor.EVENTS_ALL); // WatchMonitor.createAll(file, new SimpleWatcher(){ // @Override // public void onModify(WatchEvent<?> event, Path currentPath) { // Console.log("EVENT modify"); // } // }).start(); watchMonitor.setWatcher(new Watcher(){ @Override public void onCreate(WatchEvent<?> event, Path currentPath) { Object obj = event.context(); Console.log("创建:{}-> {}", currentPath, obj); } @Override public void onModify(WatchEvent<?> event, Path currentPath) { Object obj = event.context(); Console.log("修改:{}-> {}", currentPath, obj); } @Override public void onDelete(WatchEvent<?> event, Path currentPath) { Object obj = event.context(); Console.log("删除:{}-> {}", currentPath, obj); } @Override public void onOverflow(WatchEvent<?> event, Path currentPath) { Object obj = event.context(); Console.log("Overflow:{}-> {}", currentPath, obj); } }); //设置监听目录的最大深入,目录层级大于制定层级的变更将不被监听,默认只监听当前层级目录 watchMonitor.setMaxDepth(3); //启动监听 watchMonitor.start(); } }
1.4 监听全部事件
其实我们不必实现Watcher
的所有接口方法,Hutool同时提供了SimpleWatcher
类,只需重写对应方法即可。
同样,如果我们想监听所有事件,可以:
WatchMonitor.createAll(file, new SimpleWatcher(){ @Override public void onModify(WatchEvent<?> event, Path currentPath) { Console.log("EVENT modify"); } }).start();
createAll
方法会创建一个监听所有事件的WatchMonitor,同时在第二个参数中定义Watcher来负责处理这些变动。
1.5 延迟处理监听事件
在监听目录或文件时,如果这个文件有修改操作,JDK会多次触发modify方法,为了解决这个问题,我们定义了DelayWatcher
,此类通过维护一个Set将短时间内相同文件多次modify的事件合并处理触发,从而避免以上问题。
WatchMonitor monitor = WatchMonitor.createAll("d:/", new DelayWatcher(watcher, 500)); monitor.start();
IO流相关
文件的拷贝
// 文件的拷贝 BufferedInputStream in = FileUtil.getInputStream("d:/桌面/HuTool学习.md"); BufferedOutputStream out = FileUtil.getOutputStream("d:/桌面/HuTool学习复制.md"); long copySize = IoUtil.copy(in, out, IoUtil.DEFAULT_BUFFER_SIZE); // 拷贝文件的大小 System.out.println(copySize); System.out.println("拷贝成功"); in.close(); out.close();
文件类型判断
用于文件类型的判断,返回值为文件的类型
File file = FileUtil.file("d:/桌面/HuTool学习.md"); String type = FileTypeUtil.getType(file); //输出的是文件的格式 Console.log(type);
2 文件的读取
//默认UTF-8编码,可以在构造中传入第二个参数做为编码 FileReader fileReader = new FileReader("d:/桌面/HuTool测试.txt"); String result = fileReader.readString(); System.out.println(result);
3 文件的写入
FileWriter writer = new FileWriter("d:/桌面/HuTool测 试.txt"); writer.write("添加文本",true);
实例:
** @Override public ResponseEntity<byte[]> download(String fileId) { QueryWrapper queryWrapper=new QueryWrapper(); queryWrapper.eq("file_id",fileId); queryWrapper.orderByDesc("create_time"); queryWrapper.last("limit 1"); MeetingSignRecordFile meetingSignRecordFile = meetingSignRecordFileMapper.selectOne(queryWrapper); if (StringUtils.isBlank(meetingSignRecordFile.getPath())){ System.out.println(downloadUrl + downloadPostfix + fileId); ResponseEntity<byte[]> forEntity = restTemplate.getForEntity(downloadUrl + downloadPostfix + fileId, byte[].class); byte[] body = forEntity.getBody(); String filePath = System.getProperty("user.home") + "/jury/fileInfo/" + meetingSignRecordFile.getMc(); FileWriter fileWriter=new FileWriter(filePath); fileWriter.write(body, 0, body.length); UpdateWrapper updateWrapper=new UpdateWrapper(); meetingSignRecordFile.setPath(filePath); updateWrapper.eq("sign_form_id",meetingSignRecordFile.getSignFormId()); meetingSignRecordFileMapper.update(meetingSignRecordFile,updateWrapper); return forEntity; }else{ FileReader fileReader = new FileReader(meetingSignRecordFile.getPath()); byte[] bytes = fileReader.readBytes(); ResponseEntity<byte[]> responseEntity=new ResponseEntity<>(bytes,HttpStatus.OK); return responseEntity; } }**
4 文件追加
主要用于类似日志这种(此类只有在写入文件的时候打开文件,写入结束之后,此类不需要关闭)
File file = new File("d:/桌面/HuTool测试.txt"); FileAppender appender = new FileAppender(file, 16, true); appender.append("lolly1023"); appender.append("追加"); appender.append("成功"); appender.flush(); appender.toString();
5 文件跟随
有时候需要启动线程来“监控”文件的变化,类似于Linux下的tail -f
命令
Tailer tailer = new Tailer(FileUtil.file("d:/桌面/test.log"), Tailer.CONSOLE_HANDLER, 2); tailer.start();
实时打印文件变化的类
/** * 命令行打印的行处理器 * * @author oldlu * @since 4.5.2 */ public static class ConsoleLineHandler implements LineHandler { @Override public void handle(String line) { Console.log(line); } }
该方法会阻塞线程
6 文件名与扩展名
获取文件名
File file = FileUtil.file("d:/桌面/HuTool学习.md"); // HuTool学习.md String name = FileNameUtil.getName(file); System.out.println(name);
单独获取主文件名与扩展名
File file1 = FileUtil.file("d:/桌面/HuTool学习.md"); // "HuTool学习" String name1 = FileNameUtil.mainName(file1); System.out.println(name1); // "md" String name2 = FileNameUtil.extName(file1); System.out.println(name2);