Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀
目前支持文件后缀识别 (待完善):
文件头(magic number) | 文件扩展名(ext name) | 备注 |
---|---|---|
89504E47 | .png | PNG |
FFD8FF | .jpg | JPEG |
47494638 | .gif | GIF |
25504446 | ||
504B0304 | .zip | ZIP/DOCX/XLSX |
D0CF11E0 | .doc | DOC(老版Office) |
0x0201 | .xls | XLS(老版Office) |
7ZBCAF27 | .7z | 7-Zip |
52617221 | .rar | RAR |
494433 | .mp3 | MP3 |
000001BA | .mpg | MPEG视频 |
000001B3 | .mpg | MPEG视频 |
66747970 | .mp4 | MP4 |
4F676753 | .ogg | OGG |
424D | .bmp | BMP |
1F8B08 | .gz | GZIP |
3C3F786D6C | .xml | XML |
68746D6C3E | .html | HTML |
494E53455254494F | .sql | SQL文件 |
3C21444F435459504520 | .html | HTML |
代码:
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
public class FileExtensionDetector {
// 文件头(Magic Numbers)与文件后缀的映射表
private static final Map FILE_SIGNATURES = new HashMap();
static {
FILE_SIGNATURES.put("89504E47", ".png"); // PNG
FILE_SIGNATURES.put("FFD8FF", ".jpg"); // JPEG
FILE_SIGNATURES.put("47494638", ".gif"); // GIF
FILE_SIGNATURES.put("25504446", ".pdf"); // PDF
FILE_SIGNATURES.put("504B0304", "zip"); // ZIP / DOCX / XLSX
FILE_SIGNATURES.put("D0CF11E0", ".doc"); // DOC (老版Office)
FILE_SIGNATURES.put("0x0201", ".xls"); // XLS (老版Office)
FILE_SIGNATURES.put("7ZBCAF27", ".7z"); // 7-Zip
FILE_SIGNATURES.put("52617221", ".rar"); // RAR
FILE_SIGNATURES.put("494433", ".mp3"); // MP3
FILE_SIGNATURES.put("000001BA", ".mpg"); // MPEG 视频
FILE_SIGNATURES.put("000001B3", ".mpg"); // MPEG 视频
FILE_SIGNATURES.put("66747970", ".mp4"); // MP4
FILE_SIGNATURES.put("4F676753", ".ogg"); // OGG
FILE_SIGNATURES.put("424D", ".bmp"); // BMP
FILE_SIGNATURES.put("1F8B08", ".gz"); // GZIP
FILE_SIGNATURES.put("3C3F786D6C", ".xml"); // XML
FILE_SIGNATURES.put("68746D6C3E", ".html"); // HTML
FILE_SIGNATURES.put("494E53455254494F", ".sql"); // SQL 文件
FILE_SIGNATURES.put("3C21444F435459504520", ".html"); // HTML
}
/**
* 解析 Base64 字符串并推断文件后缀
*
* @param base64String Base64编码的文件字符串
* @return 文件的后缀名
*/
public static String getFileExtension(String base64String) {
byte[] fileData = Base64.getDecoder().decode(base64String);
String fileHeader = bytesToHex(fileData, 4);
// 通过文件头判断文件类型
for (Map.Entry entry : FILE_SIGNATURES.entrySet()) {
if (fileHeader.startsWith(entry.getKey())) {
String extension = entry.getValue();
if ("zip".equals(extension)) {
return checkZipContent(fileData); // ZIP文件需要进一步判断
}
return extension;
}
}
return "未知类型";
}
/**
* 检查 ZIP 文件的内部结构,以识别 OFD、DOCX、XLSX 或普通 ZIP
*
* @param data ZIP 文件的二进制数据
* @return 文件后缀 (.ofd, .docx, .xlsx, .zip)
*/
private static String checkZipContent(byte[] data) {
try (ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(data))) {
ZipEntry entry;
boolean hasOFD = false, hasWord = false, hasExcel = false;
// 遍历 ZIP 文件的所有条目
while ((entry = zis.getNextEntry()) != null) {
String name = entry.getName().toLowerCase();
if (name.equals("ofd.xml")) return ".ofd"; // OFD 文件
if (name.startsWith("word/")) hasWord = true; // DOCX 文件
if (name.startsWith("xl/")) hasExcel = true; // XLSX 文件
}
if (hasWord) return ".docx";
if (hasExcel) return ".xlsx";
} catch (IOException e) {
e.printStackTrace();
}
return ".zip"; // 如果未匹配到特定结构,默认为 ZIP 文件
}
/**
* 将字节数组的前 length 字节转换为十六进制字符串
*
* @param bytes 字节数组
* @param length 转换长度
* @return 十六进制字符串
*/
private static String bytesToHex(byte[] bytes, int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < Math.min(bytes.length, length); i++) {
sb.append(String.format("%02X", bytes[i]));
}
return sb.toString();
}
public static void main(String[] args) {
// 示例 Base64 字符串(替换为你要测试的 Base64)
String base64String = "UEsFBgAAAAAAAAAAAAAAAAAAAAAAAA==..."; // 这里填入你的 Base64 字符串
// 获取文件后缀并输出
String extension = getFileExtension(base64String);
System.out.println("文件后缀: " + extension);
}
}
在 Java 代码中,对于 FILE_SIGNATURES
映射表的定义中,FILE_SIGNATURES.put("504B0304", "zip");
使用 "zip"
而不是 ".zip"
是因为在代码逻辑中,我们通过检查文件内容来进一步判断 ZIP 文件的具体类型(例如 DOCX、XLSX 或 OFD)。以下是代码中的相关逻辑及其原因:
原因说明:
统一格式:
- 在一些场景下,文件名不需要带上点(
.
),而只需要后缀名的简化形式。因此,在FILE_SIGNATURES
中使用zip
而不是.zip
可能是为了保持一致性。
- 在一些场景下,文件名不需要带上点(
判断文件类型:
- 由于 ZIP 文件格式可以容纳多种文件类型(如 DOCX、XLSX),在检测到文件头为
504B0304
时,我们调用checkZipContent
方法进一步解析文件内容,以确定实际的文件类型。该方法返回的后缀名(如.docx
或.xlsx
)会在前端进行最终的呈现。
- 由于 ZIP 文件格式可以容纳多种文件类型(如 DOCX、XLSX),在检测到文件头为
代码片段说明:
在 getFileExtension
方法中,当检测到文件头为 504B0304
时,它会调用 checkZipContent
方法:
if ("zip".equals(extension)) {
return checkZipContent(fileData); // ZIP文件需要进一步判断
}
这样,checkZipContent
方法会处理 ZIP 文件并返回具体的后缀。
更新建议:
如果为了使代码的可读性更强且一致,您可以将 ZIP 文件的后缀更改为 .zip
,但是请确保在后续逻辑中进行相应的调整。以下是可能的修改:
FILE_SIGNATURES.put("504B0304", ".zip"); // 使用 .zip
并在 checkZipContent
方法中相应地处理:
if (hasWord) return ".docx"; // 如果是 Word 文档
if (hasExcel) return ".xlsx"; // 如果是 Excel 文档
总结:
选择 .zip
或 zip
实际上是风格问题,但重要的是在后续处理过程中保持一致性。根据您的需要进行调整可以增强代码的可读性和逻辑清晰度。
Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀Base64字符串根据文件头识别文件后缀 | Java Base64字符串根据文件头识别文件后缀