前言
在Java开发中,尤其是Web应用或文件处理场景中,获取文件后缀名是一个高频需求。无论是文件上传验证、类型过滤、格式校验,还是日志记录,后缀名的正确提取都是核心基础。
1. 基础方法:lastIndexOf
+ substring
定义:通过定位最后一个 .
的位置,截取后缀名。
入参:MultipartFile file
依赖:无
代码示例:
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null || originalFilename.isEmpty()) {
return "";
}
int dotIndex = originalFilename.lastIndexOf('.');
if (dotIndex == -1 || dotIndex == originalFilename.length() - 1) {
return "";
}
return originalFilename.substring(dotIndex + 1).toLowerCase();
}
执行效果:
- 文件名
report_v2.2023.xlsx
→ 返回xlsx
- 文件名
image.
→ 返回空字符串 - 文件名
.gitignore
→ 返回gitignore
2. 字符串分割:split
方法
定义:通过 .
分割文件名,取最后一个元素。
入参:MultipartFile file
依赖:无
代码示例:
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
return "";
}
String[] parts = originalFilename.split("\\.");
return parts.length > 1 ? parts[parts.length - 1].toLowerCase() : "";
}
执行效果:
- 文件名
archive.v1.7z
→ 返回7z
- 文件名
file
→ 返回空字符串
3. 正则表达式
定义:通过正则匹配最后一个 .
后的字符串。
入参:MultipartFile file
依赖:无
代码示例:
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
return "";
}
Pattern pattern = Pattern.compile("\\.(\\w+)$");
Matcher matcher = pattern.matcher(originalFilename);
return matcher.find() ? matcher.group(1).toLowerCase() : "";
}
执行效果:
- 文件名
document.pdf
→ 返回pdf
- 文件名
file.tar.gz
→ 返回gz
4. Apache Commons IO 的 FilenameUtils
定义:使用 Apache Commons IO 的工具类。
入参:MultipartFile file
依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>9.0.0</version>
</dependency>
代码示例:
import org.apache.commons.io.FilenameUtils;
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
return FilenameUtils.getExtension(originalFilename).toLowerCase();
}
执行效果:
- 文件名
file.txt
→ 返回txt
- 文件名
file.
→ 返回空字符串
5. Spring框架的 StringUtils
定义:使用 Spring 的工具类。
入参:MultipartFile file
依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>6.0.10</version>
</dependency>
代码示例:
import org.springframework.util.StringUtils;
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
return StringUtils.getFilenameExtension(originalFilename);
}
执行效果:
- 文件名
image.jpg
→ 返回jpg
- 返回值为
null
时需注意空指针(如file
无扩展名)。
6. 使用 File
类
定义:通过构造 File
对象提取文件名。
入参:MultipartFile file
依赖:无
代码示例:
import java.io.File;
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
return "";
}
File tempFile = new File(originalFilename);
String name = tempFile.getName();
int dotIndex = name.lastIndexOf('.');
return (dotIndex > 0 && dotIndex < name.length() - 1)
? name.substring(dotIndex + 1).toLowerCase()
: "";
}
执行效果:
- 文件名
data.csv
→ 返回csv
- 文件名
config.
→ 返回空字符串
7. Java NIO的 Paths
类
定义:通过 java.nio.file
包处理路径。
入参:MultipartFile file
依赖:无
代码示例:
import java.nio.file.Path;
import java.nio.file.Paths;
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
String originalFilename = file.getOriginalFilename();
if (originalFilename == null) {
return "";
}
Path path = Paths.get(originalFilename);
String name = path.getFileName().toString();
return name.substring(name.lastIndexOf('.') + 1).toLowerCase();
}
执行效果:
- 文件名
report.pdf
→ 返回pdf
- 跨平台兼容性好(如路径
/home/file.txt
→ 提取txt
)。
8. 结合MIME类型验证
定义:通过 MultipartFile.getContentType()
验证后缀。
入参:MultipartFile file
依赖:无
代码示例:
public static boolean validateFile(MultipartFile file) {
String ext = getExtension(file); // 使用上述任意方法
String contentType = file.getContentType();
return ext.equals("jpg") && contentType.equals("image/jpeg");
}
执行效果:
- 文件名
image.jpg
且 MIME 为image/jpeg
→ 返回true
- 文件名
image.png
但 MIME 为image/jpeg
→ 返回false
9. 自定义枚举过滤
定义:通过枚举限定允许的后缀。
入参:MultipartFile file
代码示例:
enum FileType {
PNG, JPG, JPEG, GIF;
public static boolean isValid(String ext) {
for (FileType type : FileType.values()) {
if (type.name().equalsIgnoreCase(ext)) {
return true;
}
}
return false;
}
}
public static String getValidExtension(MultipartFile file) {
String ext = getExtension(file);
return FileType.isValid(ext) ? ext : "";
}
执行效果:
- 文件名
photo.jpg
→ 返回jpg
- 文件名
image.bmp
→ 返回空字符串
10. 使用Lombok的 @Cleanup
简化代码
定义:通过 Lombok 减少资源管理代码。
入参:MultipartFile file
依赖:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.28</version>
<scope>provided</scope>
</dependency>
代码示例:
import lombok.Cleanup;
public static String getExtension(MultipartFile file) {
if (file == null) {
return "";
}
@Cleanup
InputStream inputStream = file.getInputStream();
// 其他逻辑(如读取文件内容)
return "ext"; // 示例返回值
}
执行效果:
- 自动关闭
inputStream
,无需手动管理资源。
方法对比表
方法 | 依赖 | 边界处理 | 性能 | 适用场景 |
---|---|---|---|---|
lastIndexOf + substring | 无 | 完善(需手动处理) | 高 | 简单场景,无依赖要求 |
split | 无 | 简单(需数组长度判断) | 中 | 快速实现,无特殊需求 |
正则表达式 | 无 | 灵活(正则可扩展) | 中 | 需复杂匹配时 |
Apache Commons IO | commons-io | 自动处理 | 高 | 需多文件操作功能 |
Spring StringUtils | spring-core | 自动处理 | 高 | Spring生态内使用 |
File 类 | 无 | 基础 | 中 | 需路径处理时 |
Java NIO Paths | 无 | 基础 | 中 | 现代API,跨平台需求 |
MIME类型验证 | 无 | 依赖MIME类型 | 高 | 安全验证场景 |
最佳实践建议
-
依赖选择:
- 零依赖场景:优先使用
lastIndexOf
或split
。 - 复杂需求:使用 Apache Commons IO 或 Spring 的
StringUtils
。
- 零依赖场景:优先使用
-
边界情况处理:
- 文件名以
.
开头(如.gitignore
):返回后缀gitignore
。 - 文件名无扩展名(如
file
):返回空字符串。 - 文件名以
.
结尾(如file.
):返回空字符串。
- 文件名以
-
后缀统一小写:
- 使用
toLowerCase()
避免大小写敏感问题(如JPG
→jpg
)。
- 使用
-
安全验证:
- 结合MIME类型与后缀双重校验(如
image/jpeg
与jpg
)。
- 结合MIME类型与后缀双重校验(如
总结
针对 MultipartFile
的后缀名获取,选择需结合项目需求:
- 基础场景:推荐
lastIndexOf
或 Apache Commons IO。 - Spring生态:直接使用
StringUtils.getFilenameExtension
。 - 安全敏感场景:结合MIME类型验证。