03-file
1. FileTypeUtil
- 文件上传时,需要判断文件类型。但是又不能简单的通过扩展名来判断(防止恶意脚本等上传到服务器上),于是需要在服务端通过读取文件的首部几个字节值来判断常用的文件类型
File file = FileUtil.file("/Users/listao/Pictures/Typora/9361712596048_.pic.jpg");
String type = FileTypeUtil.getType(file);
// 输出 jpg则说明确实为jpg文件
Console.log("type: {}", type);
1. 原理和局限性
- 通过读取文件流中前N个byte值来判断文件类型,在类中通过Map形式将常用的文件类型做了映射,这些映射都是网络上搜集而来。只能识别有限的几种文件类型。但是这些类型已经涵盖了常用的图片、音频、视频、Office文档类型,可以应对大部分的使用场景
对于某些文本格式的文件并不能通过首部byte判断其类型,eg:
JSON
,这类文件本质上是文本文件,应该读取其文本内容,通过其语法判断类型
2. 自定义类型
- 为了提高
FileTypeUtil
的扩展性,通过putFileType
方法可以自定义文件类型
FileTypeUtil.putFileType("ffd8ffe000104a464946", "new_jpg");
- 第一个参数是文件流的前N个byte的16进制表示,可以读取自定义文件查看,选取一定长度即可(长度越长越精确),第二个参数就是文件类型,然后使用
FileTypeUtil.getType
即可
注意 xlsx、docx本质上是各种XML打包为zip的结果,因此会被识别为zip格式
2. FileNameUtil
String path = "/Users/listao/mca/listao_doc/docs/dev/01_maven/01_Maven.md";
File file = FileUtil.file(path);
// 01_Maven.md
String getName = FileNameUtil.getName(file);
System.out.println("getName = " + getName);
// 01_Maven
String mainName = FileNameUtil.mainName(file);
System.out.println("mainName = " + mainName);
// md
String extName = FileNameUtil.extName(file);
System.out.println("extName = " + extName);
3. FileUtil
- 文件操作:包括文件目录的新建、删除、复制、移动、改名等
- 文件判断:判断文件或目录是否非空,是否为目录,是否为文件等等
- 绝对路径:针对
ClassPath
中的文件转换为绝对路径文件 - 文件名:主文件名,扩展名的获取
- 读操作:包括类似
IoUtil
中的getReader
、readXXX
操作 - 写操作:包括
getWriter
和writeXXX
操作
在FileUtil
中,努力让方法名与Linux相一致
ls
:列出目录和文件touch
:创建文件,如果父目录不存在也自动创建mkdir
:创建目录,会递归创建每层目录del
:删除文件或目录(递归删除,不判断是否为空),这个方法相当于Linux的delete命令copy
:拷贝文件或目录
4. FileReader
// 默认UTF-8编码,可以在构造中传入第二个参数做为编码
FileReader fileReader = new FileReader("test.properties");
String result = fileReader.readString();
FileReader
提供了以下方法来快速读取文件内容:
readBytes
readString
readLines
同时,此类还提供了以下方法用于转换为流或者BufferedReader
:
getReader
getInputStream
5. FileWriter
FileWriter writer = new FileWriter("test.properties");
writer.write("test");
写入文件分为追加模式和覆盖模式两类,追加模式用append
,覆盖模式用write
,同时也提供了一个write()
,第二个参数是可选覆盖模式
getOutputStream
getWriter
getPrintWriter
6. FileAppender
- 此对象持有一个文件,在内存中积累一定量的数据后统一追加到文件,此类只有在写入文件时打开文件,并在写入结束后关闭。因此此类不需要关闭
- 在调用
append()
后会缓存于内存,只有超过容量后才会一次性写入文件,因此内存中随时有剩余未写入文件的内容,在最后必须调用flush()
将剩余内容刷入文件 - 也就是说,这是一个支持缓存的文件内容追加器。此类主要用于类似于日志写出这类需求
FileAppender appender = new FileAppender(file, 16, true);
appender.append("123");
appender.append("abc");
appender.append("xyz");
appender.flush();
appender.toString();
7. Tailer
- 启动一个线程实时“监控”文件的变化,eg:有新内容写出到文件时,可以及时打印出来,类似于Linux下的
tail -f
Tailer tailer = new Tailer(FileUtil.file("f:/test/test.log"), Tailer.CONSOLE_HANDLER, 2);
tailer.start();
- 其中
Tailer.CONSOLE_HANDLER
表示文件新增内容默认输出到控制台
/**
* 命令行打印的行处理器
*/
public static class ConsoleLineHandler implements LineHandler {
@Override
public void handle(String line) {
Console.log(line);
}
}
也可以自定义LineHandler
来处理每一行数据
注意:此方法会阻塞当前线程
99. Hands_on
1. 输出文件
String path = "/Users/listao/tmp/ooxx.txt";
// 1. 不存在目录,创建目录。不存在文件,创建文件
File touch = FileUtil.touch(path);
FileWriter writer = new FileWriter(touch);
// 2. 删除原内容,写入
writer.write("ooxx", false);
2. 修改文件
String path = "/Users/listao/tmp/ooxx.txt";
// 1. 不存在目录,创建目录。不存在文件,创建文件
File touch = FileUtil.touch(path);
FileReader reader = new FileReader(touch);
List<String> lines = reader.readLines();
ListIterator<String> iterator = lines.listIterator();
while (iterator.hasNext()) {
String next = iterator.next();
if (next.contains("ooxx")) {
// 2. 替换
String ox = next.replace("ox", "**");
iterator.set(ox);
}
}
FileWriter writer = new FileWriter(touch);
// 3. 删除原内容,写入
writer.writeLines(lines);