Java 讀取圖片的mimeType的方法
一、問(wèn)題描述
在項(xiàng)目開(kāi)發(fā)的時(shí)候,我們經(jīng)常會(huì)遇到一類(lèi)文件上傳的問(wèn)題,就是獲取圖片是哪種格式。很多情況下,很多人都是用后綴名去判斷,如下所示。
if(filename.endsWith(".png") || filename.endsWith(".jpg"))
{
//保存圖片
}else{
throw new IOException("Error file format !");
}
但是這種方式相當(dāng)不可靠,我們可以嘗試將zip文件、rmvb文件、css、js修改后綴名位jpg或者png上傳,也可以上傳到服務(wù)器,這就造成我們服務(wù)器上出現(xiàn)了臟數(shù)據(jù)。此外,對(duì)于有些圖片文件,修改成錯(cuò)誤的擴(kuò)展名,有些瀏覽器可能無(wú)法顯示出此圖片。
二、解決方案
在計(jì)算機(jī)系統(tǒng)中,媒體類(lèi)型的文件都有【標(biāo)識(shí)符】,zip、圖片本身屬于媒體文件,因此我們可以通過(guò)編解碼的方式判斷圖片是否合法。
1、判斷標(biāo)示方法
private static boolean isBMP(byte[] buf){
byte[] markBuf = "BM".getBytes(); //BMP圖片文件的前兩個(gè)字節(jié)
return compare(buf, markBuf);
}
private static boolean isICON(byte[] buf) {
byte[] markBuf = {0, 0, 1, 0, 1, 0, 32, 32};
return compare(buf, markBuf);
}
private static boolean isWEBP(byte[] buf) {
byte[] markBuf = "RIFF".getBytes(); //WebP圖片識(shí)別符
return compare(buf, markBuf);
}
private static boolean isGIF(byte[] buf) {
byte[] markBuf = "GIF89a".getBytes(); //GIF識(shí)別符
if(compare(buf, markBuf))
{
return true;
}
markBuf = "GIF87a".getBytes(); //GIF識(shí)別符
if(compare(buf, markBuf))
{
return true;
}
return false;
}
private static boolean isPNG(byte[] buf) {
byte[] markBuf = {(byte) 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A}; //PNG識(shí)別符
// new String(buf).indexOf("PNG")>0 //也可以使用這種方式
return compare(buf, markBuf);
}
private static boolean isJPEGHeader(byte[] buf) {
byte[] markBuf = {(byte) 0xff, (byte) 0xd8}; //JPEG開(kāi)始符
return compare(buf, markBuf);
}
private static boolean isJPEGFooter(byte[] buf)//JPEG結(jié)束符
{
byte[] markBuf = {(byte) 0xff, (byte) 0xd9};
return compare(buf, markBuf);
}
2、核心方法
/**
* 獲取文件的mimeType
* @param filename
* @return
*/
private static String getMimeType(String filename){
try {
String mimeType = readType(filename);
return String.format("image/%s", mimeType);
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 讀取文件類(lèi)型
* @param filename
* @return
* @throws IOException
*/
private static String readType(String filename) throws IOException {
FileInputStream fis = null;
try {
File f = new File(filename);
if(!f.exists() || f.isDirectory() || f.length()<8) {
throw new IOException("the file ["+f.getAbsolutePath()+"] is not image !");
}
fis= new FileInputStream(f);
byte[] bufHeaders = readInputStreamAt(fis,0,8);
if(isJPEGHeader(bufHeaders))
{
long skiplength = f.length()-2-8; //第一次讀取時(shí)已經(jīng)讀了8個(gè)byte,因此需要減掉
byte[] bufFooters = readInputStreamAt(fis, skiplength, 2);
if(isJPEGFooter(bufFooters))
{
return "jpeg";
}
}
if(isPNG(bufHeaders))
{
return "png";
}
if(isGIF(bufHeaders)){
return "gif";
}
if(isWEBP(bufHeaders))
{
return "webp";
}
if(isBMP(bufHeaders))
{
return "bmp";
}
if(isICON(bufHeaders))
{
return "ico";
}
throw new IOException("the image's format is unkown!");
} catch (FileNotFoundException e) {
throw e;
}finally{
try {
if(fis!=null) fis.close();
} catch (Exception e) {
}
}
}
/**
* 標(biāo)示一致性比較
* @param buf 待檢測(cè)標(biāo)示
* @param markBuf 標(biāo)識(shí)符字節(jié)數(shù)組
* @return 返回false標(biāo)示標(biāo)示不匹配
*/
private static boolean compare(byte[] buf, byte[] markBuf) {
for (int i = 0; i < markBuf.length; i++) {
byte b = markBuf[i];
byte a = buf[i];
if(a!=b){
return false;
}
}
return true;
}
/**
*
* @param fis 輸入流對(duì)象
* @param skiplength 跳過(guò)位置長(zhǎng)度
* @param length 要讀取的長(zhǎng)度
* @return 字節(jié)數(shù)組
* @throws IOException
*/
private static byte[] readInputStreamAt(FileInputStream fis, long skiplength, int length) throws IOException
{
byte[] buf = new byte[length];
fis.skip(skiplength); //
int read = fis.read(buf,0,length);
return buf;
}
3、測(cè)試代碼
正常測(cè)試
public class ImageType {
public static void main(String[] args) {
String filename = "oschina.jpg";
String type = getMimeType(filename);
System.out.println(type);
}
}
輸出
image/jpeg
修改擴(kuò)展名測(cè)試
①修改oschina.jpeg為oschina.png
②復(fù)制oschina.png刪除擴(kuò)展名
public class ImageType {
public static void main(String[] args) {
String filename = "oschina.png";
String type = getMimeType(filename);
System.out.println(type);
filename = "oschina";
type = getMimeType(filename);
System.out.println(type);
}
}
輸出
image/jpeg
image/jpeg
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java中JDBC事務(wù)與JTA分布式事務(wù)總結(jié)與區(qū)別
Java事務(wù)的類(lèi)型有三種:JDBC事務(wù)、JTA(Java Transaction API)事務(wù)、容器事務(wù),本文詳細(xì)介紹了JDBC事務(wù)與JTA分布式事務(wù),有需要的可以了解一下。2016-11-11
idea?maven?經(jīng)常主目錄自動(dòng)變回默認(rèn)的解決方法
很多朋友反映idea?maven?經(jīng)常主目錄自動(dòng)變回默認(rèn),遇到這樣的問(wèn)題真的很頭疼,該如何解決呢?下面小編給大家介紹下idea?maven目錄變回默認(rèn)的解決方法,需要的朋友可以參考下2022-08-08
SpringBoot創(chuàng)建動(dòng)態(tài)定時(shí)任務(wù)的幾種方式小結(jié)
SpringBoot提供了多種實(shí)現(xiàn)定時(shí)任務(wù)的方式,包括使用@Scheduled注解、SchedulingConfigurer接口、TaskScheduler接口和Quartz框架,@Scheduled適合簡(jiǎn)單的定時(shí)任務(wù),文中通過(guò)代碼示例介紹的非常詳細(xì),需要的朋友可以參考下2024-10-10
基于Java編寫(xiě)一個(gè)粽子大作戰(zhàn)小游戲
端午節(jié),又稱(chēng)龍舟節(jié)、重午節(jié),是中國(guó)的傳統(tǒng)節(jié)日之一,每年農(nóng)歷五月初五慶祝,雖然端午假期已經(jīng)過(guò)去了,小編還是用Java編寫(xiě)了一個(gè)粽子大作戰(zhàn)小游戲,感興趣的可以了解一下2023-06-06
springboot實(shí)戰(zhàn)權(quán)限管理功能圖文步驟附含源碼
這篇文章主要為大家介紹了springboot實(shí)戰(zhàn)權(quán)限管理功能圖文步驟及示例源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
SpringBoot項(xiàng)目整合達(dá)夢(mèng)數(shù)據(jù)庫(kù)詳解(MYSQL轉(zhuǎn)換達(dá)夢(mèng)數(shù)據(jù)庫(kù))
這篇文章主要為大家詳細(xì)介紹了MYSQL轉(zhuǎn)換達(dá)夢(mèng)數(shù)據(jù)庫(kù)以及SpringBoot項(xiàng)目整合達(dá)夢(mèng)數(shù)據(jù)庫(kù)的相關(guān)教程,文中的示例代碼講解詳細(xì),需要的可以參考下2025-03-03
SpringBoot使用@EnableAutoConfiguration實(shí)現(xiàn)自動(dòng)配置詳解
你有想過(guò)SpringBoot為什么能夠自動(dòng)的幫我們創(chuàng)建一個(gè)Bean對(duì)象么?或許在我們使用的時(shí)候只需要在自己自定義的配置文件中加入@Bean對(duì)象就可以,但SpringBoot是如何來(lái)創(chuàng)建的呢2022-08-08

