Java 讀取圖片的mimeType的方法
一、問題描述
在項目開發(fā)的時候,我們經(jīng)常會遇到一類文件上傳的問題,就是獲取圖片是哪種格式。很多情況下,很多人都是用后綴名去判斷,如下所示。
if(filename.endsWith(".png") || filename.endsWith(".jpg")) { //保存圖片 }else{ throw new IOException("Error file format !"); }
但是這種方式相當不可靠,我們可以嘗試將zip文件、rmvb文件、css、js修改后綴名位jpg或者png上傳,也可以上傳到服務器,這就造成我們服務器上出現(xiàn)了臟數(shù)據(jù)。此外,對于有些圖片文件,修改成錯誤的擴展名,有些瀏覽器可能無法顯示出此圖片。
二、解決方案
在計算機系統(tǒng)中,媒體類型的文件都有【標識符】,zip、圖片本身屬于媒體文件,因此我們可以通過編解碼的方式判斷圖片是否合法。
1、判斷標示方法
private static boolean isBMP(byte[] buf){ byte[] markBuf = "BM".getBytes(); //BMP圖片文件的前兩個字節(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圖片識別符 return compare(buf, markBuf); } private static boolean isGIF(byte[] buf) { byte[] markBuf = "GIF89a".getBytes(); //GIF識別符 if(compare(buf, markBuf)) { return true; } markBuf = "GIF87a".getBytes(); //GIF識別符 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識別符 // new String(buf).indexOf("PNG")>0 //也可以使用這種方式 return compare(buf, markBuf); } private static boolean isJPEGHeader(byte[] buf) { byte[] markBuf = {(byte) 0xff, (byte) 0xd8}; //JPEG開始符 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; } /** * 讀取文件類型 * @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; //第一次讀取時已經(jīng)讀了8個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) { } } } /** * 標示一致性比較 * @param buf 待檢測標示 * @param markBuf 標識符字節(jié)數(shù)組 * @return 返回false標示標示不匹配 */ 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 輸入流對象 * @param skiplength 跳過位置長度 * @param length 要讀取的長度 * @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、測試代碼
正常測試
public class ImageType { public static void main(String[] args) { String filename = "oschina.jpg"; String type = getMimeType(filename); System.out.println(type); } }
輸出
image/jpeg
修改擴展名測試
①修改oschina.jpeg為oschina.png
②復制oschina.png刪除擴展名
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
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
解決springboot 連接 mysql 時報錯 using password: NO的方案
在本篇文章里小編給大家整理了關于解決springboot 連接 mysql 時報錯 using password: NO的方案,有需要的朋友們可以學習下。2020-01-01Java操作mongodb增刪改查的基本操作實戰(zhàn)指南
MongoDB是一個基于分布式文件存儲的數(shù)據(jù)庫,由c++語言編寫,旨在為WEB應用提供可擴展的高性能數(shù)據(jù)存儲解決方案,下面這篇文章主要給大家介紹了關于Java操作mongodb增刪改查的基本操作實戰(zhàn)指南,需要的朋友可以參考下2023-05-05Java多線程并發(fā)的指令重排序問題及volatile寫屏障原理詳解
這篇文章主要介紹了Java多線程并發(fā)的指令重排序問題及volatile寫屏障原理詳解,指令重排序是編譯器或處理器為了提高性能而對指令執(zhí)行順序進行重新排列的優(yōu)化技術,需要的朋友可以參考下2024-01-01使用Java和SpringBoot實現(xiàn)服務器發(fā)送事件(Server-Sent Events)
使用Java開發(fā)web應用,大多數(shù)時候我們提供的接口返回數(shù)據(jù)都是一次性完整返回,有些時候,我們也需要提供流式接口持續(xù)寫出數(shù)據(jù),以下提供一種簡單的方式,本文給大家介紹了如何在Java web中實現(xiàn)服務器發(fā)送事件,需要的朋友可以參考下2024-02-02