摘要:我们上传文件经常需要判断文件后缀名,直接通过源文件名称有时候会不太准确,所以我们需要通过文件的"魔术数字"来判断,更合理的操作文件。
原理
采用的源码来自于
hutool
的工具类,推荐使用这个工具类,可以自己在这个工具类上增强。
引入maven
xml
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
FileTypeUtil
java
/**
* 根据文件流的头部信息获得文件类型<br>
* 注意此方法会读取头部一些bytes,造成此流接下来读取时缺少部分bytes<br>
* 因此如果想复用此流,流需支持{@link InputStream#reset()}方法。
* @param in {@link InputStream}
* @param isExact 是否精确匹配,如果为false,使用前64个bytes匹配,如果为true,使用前8192bytes匹配
* @return 类型,文件的扩展名,未找到为{@code null}
* @throws IORuntimeException 读取流引起的异常
*/
public static String getType(InputStream in,boolean isExact) throws IORuntimeException {
return isExact
?getType(IoUtil.readHex8192Upper(in))
:getType(IoUtil.readHex64Upper(in));
}
FileMagicNumber
改枚举中定义了常见的文件魔术数字,查询出来就用来对比
- 如
jpg
的文件以ffd8ff
开头
测试案例
单元测试
ini
@Test
public void test03(){
String type = FileTypeUtil.getType(new File("C:\\Users\\lanzhuo\\Pictures\\u=3717268932,170151031&fm=30&app=106&f=JPEG.jpg"));
FileMagicNumber fileMagicNumber = Arrays.stream(FileMagicNumber.values()).filter(v -> ObjectUtil.equal(v.getExtension(), type)).findFirst().orElse(null);
System.out.println(type);
System.out.println(fileMagicNumber.getMimeType());
String type1 = FileTypeUtil.getType(new File("C:\\Users\\lanzhuo\\Pictures\\检修手册.doc"));
FileMagicNumber fileMagicNumber1 = Arrays.stream(FileMagicNumber.values()).filter(v -> ObjectUtil.equal(v.getExtension(), type1)).findFirst().orElse(null);
System.out.println(type1);
System.out.println(fileMagicNumber1.getMimeType());
}
- 结果
bash
jpg
image/jpeg
doc
application/msword
基于SpringBoot
的使用案例
Springboot
的预览文件不能制定文件名,否则会变为下载,切记
java
@GetMapping("/download")
public void download(HttpServletResponse response,String fileName) throws Exception{
File file = new File(fileUploadProperties.getLocalStorage()+fileName);
if (!file.exists() || !file.isFile()){
return;
}
InputStream inputStream = Files.newInputStream(Paths.get(fileUploadProperties.getLocalStorage() + fileName));
response.reset();
response.setContentType(this.generateDownloadContentType(Files.newInputStream(Paths.get(fileUploadProperties.getLocalStorage() + fileName))));
response.setHeader("Content-Disposition", "attachment;filename=" + new String(fileName.getBytes("UTF-8"),"ISO8859-1"));
ServletOutputStream outputStream = response.getOutputStream();
byte[] b = new byte[1024];
int len;
try {
while((len = inputStream.read(b)) > 0) {
outputStream.write(b, 0, len);
}
} finally {
inputStream.close();
}
}
@GetMapping("/preview")
public void preview(HttpServletResponse response,String fileName) throws Exception{
File file = new File(fileUploadProperties.getLocalStorage()+fileName);
if (!file.exists() || !file.isFile()){
return;
}
InputStream inputStream = Files.newInputStream(Paths.get(fileUploadProperties.getLocalStorage() + fileName));
response.reset();
ServletOutputStream outputStream = response.getOutputStream();
byte[] b = new byte[1024];
int len;
try {
while((len = inputStream.read(b)) > 0) {
outputStream.write(b, 0, len);
}
} finally {
inputStream.close();
}
}
/**
* 获取文件类型
* @param inputStream
* @return
* @throws Exception
*/
private String generateDownloadContentType(InputStream inputStream) throws Exception{
String type = FileTypeUtil.getType(inputStream);
inputStream.close();
FileMagicNumber fileMagicNumber = Arrays.stream(FileMagicNumber.values()).filter(v -> ObjectUtil.equal(v.getExtension(), type)).findFirst().orElse(null);
return null != fileMagicNumber && null != fileMagicNumber.getMimeType() ? fileMagicNumber.getMimeType() : "application/octet-stream";
}