由于自身项目需要,需要实现一个文件资源管理器,为了UI的美观,必须根据文件类型加载对应的SVG图片,那么如何确定文件类型呢?
1.匹配文件类型
这里我主要使用Files.probeContentType()静态函数获取文件的MIME类型,如果你非要使用文件尾缀,可以不要看下面了,按你自己的想法来
首先贴上完整枚举类,用枚举类对象表示文件类型
import lombok.Getter;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
/**
* @Classname FileType
* @Description 文件类型枚举
* @Version 1.0.0
* @Date 2024/9/23 23:03
* @Created by sinevil
*/
@Getter
public enum FileType {
Directory("application/x-directory"),
//文本文件
TXT("text/plain"),
PDF("application/pdf"),
DOC("application/msword"),
DOCX("application/vnd.openxmlformats - officedocument.wordprocessingml.document"),
RTF("text/rtf"),
// 压缩文件
ZIP("application/zip"),
RAR("application/x-rar-compressed"),
Z7("application/x-7z-compressed"),
TAR("application/x-tar"),
GZ("application/gzip"),
BZ2("application/x - bzip2"),
//可执行文件
EXE("application/octet-stream"),
BAT("application/bat"),
SH("application/x-shellscript"),
MSI("application/x-msi"),
//表格文件
XLS("application/vnd.ms-excel"),
XLSX("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"),
CSV("text/csv"),
ODS("application/vnd.oasis.opendocument.spreadsheet"),
//演示文稿文件
PPT("application/vnd.ms-powerpoint"),
PPTX("application/vnd.openxmlformats - officedocument.presentationml.presentation"),
ODP("application/vnd.oasis.opendocument.presentation"),
JSON("application/json"),
DLL("application/x-msdownload"),
HTML("text/html"),
XML("text/xml"),
AUDIO("audio/*"),
VIDEO("video/*"),
IMAGE("image/*"),
OTHER("*/*");
private final String mimeType;
FileType(String mimeType) {
this.mimeType = mimeType;
}
// 新增的用于存储带通配符的FileType列表
private static final Map<String,FileType> RegexPatternMap = new HashMap<>();
static {
// 在类加载时初始化将带通配符的FileType列表
String var;
for (FileType fileType : values()) {
if (fileType != FileType.OTHER) {
var = fileType.mimeType;
if (var.contains("*")) {
RegexPatternMap.put(transformToRegex(var), fileType);
}
}
}
}
/**
* 转化带*号的字符串,将其转化为正则表达式
* "audio/*" "audio/.*"
*
* @param var1 含有*的字符串
* @return
*/
private static String transformToRegex(String var1){
int asteriskIndex = var1.indexOf("*");
if (asteriskIndex+1 < var1.length())
return var1.substring(0, asteriskIndex) + ".*" + transformToRegex(var1.substring(asteriskIndex+1));
else return var1.substring(0, asteriskIndex) + ".*";
}
public static FileType fromMimeType(String mimeType) {
if (mimeType != null){
// 使用正则进行匹配
for (String regex : RegexPatternMap.keySet()) {
if (mimeType.matches(regex))
return RegexPatternMap.get(regex);
}
for (FileType fileType : values()) {
String type = fileType.getMimeType();
if (type.equals(mimeType))
return fileType;
}
return OTHER;
}
return OTHER;
}
/**
* 根据Path对象获取MIMETYPE字符串
* @param path
* @return
*/
public static FileType getFileType(Path path){
if (Files.isDirectory(path))
return FileType.Directory;
try {
return FileType.fromMimeType(Files.probeContentType(path));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 根据File对象获取MIMETYPE字符串
* @return
*/
public static FileType getFileType(File file){
return getFileType(file.toPath());
}
}
枚举类的核心是
public static FileType fromMimeType(String mimeType) {
if (mimeType != null){
// 使用正则进行匹配
for (String regex : RegexPatternMap.keySet()) {
if (mimeType.matches(regex))
return RegexPatternMap.get(regex);
}
for (FileType fileType : values()) {
String type = fileType.getMimeType();
if (type.equals(mimeType))
return fileType;
}
return OTHER;
}
return OTHER;
}
根据传入的MEME类型字符串返回对应的FileType对象,这里先对传入的memeType进行非空判断,因为Java自带的Mime类型获取器支持的类型比较少,当遇到不支持的类型时,Files.probeContentType()会返回null。之后首先对能够进行通配的Audio、Video、Image类型的文件进行匹配,之后再对不能统配的进行匹配。
2. 根据文件类型创建对象
获取文件类型后就需要根据文件类型创建对应的对象
/**
* @Classname FileInfoFactory
* @Description 文件信息工厂,用于根据文件类型创建对应的信息类对应
* @Version 1.0.0
* @Date 2024/11/25 21:46
* @Created by sinevil
*/
public class FileInfoFactory {
// 使用Map来存储文件类型与对应的创建信息类对象的函数
private static final Map<FileType, Supplier<? extends BasicInfo>> FILE_TYPE_TO_CREATOR_MAP = new HashMap<>();
static {
// 初始化Map,将每个文件类型与对应的创建函数关联起来
FILE_TYPE_TO_CREATOR_MAP.put(FileType.Directory, CatalogueInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.VIDEO,VideoFileInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.AUDIO,AudioFileInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.IMAGE,ImageFileInfo::new);
//文本文件
FILE_TYPE_TO_CREATOR_MAP.put(FileType.TXT, TextInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.PDF, TextInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.DOC, TextInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.DOCX, TextInfo::new);
FILE_TYPE_TO_CREATOR_MAP.put(FileType.RTF, TextInfo::new);
}
public static BasicInfo createFileInfoObject(Path path){
FileType fileType = FileType.getFileType(path);
Supplier<? extends BasicInfo> creator = FILE_TYPE_TO_CREATOR_MAP.get(fileType);
if (creator == null) {
// 如果没有找到对应的创建函数,默认创建BasicFileInfo对象
return new BasicInfo(path);
}
return creator.get().init(path);
}
}
这里需要用到Map,以FileType对象为键,对应信息类的构造函数为值,当传入一个路径时会先获取其fileType ,然后通过map获取静态绑定好的构造函数,并获取对象。
可以使多个FileType类型对应一个Info,因为文件的属性就那些,这里贴上文件的基本信息类。
对于图片视频等不可修改文件可以通过继承添加“最后访问时间”属性,对于文本等可修改文件,则添加“最后访问时间”和“最后修改时间”属性。
@Data
@AllArgsConstructor
public class BasicInfo implements SVGOperate {
protected static Map<String,String> SVGMap = new HashMap<>();
protected Path path;
protected BasicFileAttributes attributes;
protected String absolutePath;
protected String name;
protected FileType fileType;
protected String type;
protected Long size;
protected Boolean isDirectory;
protected LocalDateTime creationTime;
static {
SVGMap.put("unknown","imgs/svg/file/unknown.svg");
}
public BasicInfo(Path path){
this.path = path;
this.absolutePath = path.toString();
this.name = String.valueOf(path.getFileName());
if (Objects.equals(this.name, "null"))
this.name = path.toString();
try {
this.attributes = Files.readAttributes(path, BasicFileAttributes.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
this.size = this.attributes.size();
this.isDirectory = attributes.isDirectory();
if (this.isDirectory){
this.fileType = FileType.Directory;
this.type = "directory";
}
else {
this.fileType = FileType.getFileType(path);
this.type = getFileExtension(this.path);
}
this.creationTime = LocalDateTime.ofInstant(this.attributes.creationTime().toInstant(), ConfigConstant.ZONEID);
}
public BasicInfo(){}
/**
* 使用空参构造方法创建对象时调用此方法初始化类对象
* @param path
*/
public BasicInfo init(Path path){
this.path = path;
this.absolutePath = path.toString();
this.name = String.valueOf(path.getFileName());
if (Objects.equals(this.name, "null"))
this.name = path.toString();
try {
this.attributes = Files.readAttributes(path, BasicFileAttributes.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
this.size = this.attributes.size();
this.isDirectory = attributes.isDirectory();
if (this.isDirectory){
this.fileType = FileType.Directory;
this.type = "directory";
}
else {
this.fileType = FileType.getFileType(path);
this.type = getFileExtension(this.path);
}
return this;
}
public String getSVG(){
return SVGMap.get("unknown");
}
protected String getSVG(String type){
String svg;
svg = SVGMap.get(type);
if (svg==null)
return getSVG();
return svg;
}
/**
* 根据Path对象获取文件的后缀名
* 如果是目录文件则返回"directory"
* @param path
* @return
*/
public static String getFileExtension(Path path) {
String fileName = String.valueOf(path.getFileName());
int lastIndexOfDot = fileName.lastIndexOf('.');
if (lastIndexOfDot > 0 && lastIndexOfDot < fileName.length() - 1) {
return fileName.substring(lastIndexOfDot + 1);
}
return "directory";
}
/**
* 返回当前文件是否是目录
* @return
*/
public boolean isDirectory(){
return this.isDirectory;
}