在Java中确定文件类型
以編程方式確定文件的類型可能非常棘手,并且已經提出并實現了許多基于內容的文件標識方法。 Java中有幾種可用于檢測文件類型的實現,其中大多數很大程度上或完全基于文件的擴展名。 這篇文章介紹了Java中最常見的文件類型檢測實現。
本文介紹了幾種在Java中識別文件類型的方法。 簡要描述每種方法,并用代碼清單進行說明,然后將其與輸出相關聯,該輸出演示如何根據擴展名鍵入不同的公用文件。 某些方法是可配置的,但是除非另有說明,否則此處顯示的所有示例均使用開箱即用提供的“默認”映射。
關于示例
這篇文章中顯示的屏幕快照是針對某些主題文件運行的每個列出的代碼片段,這些主題文件是為了測試Java中文件類型檢測的不同實現而創建的。 在介紹這些方法并演示每種方法檢測到的類型之前,我將列出要測試的文件,它們的名稱以及它們的真實名稱。
| ActualXml.xml | XML文件 | XML格式 | 是 |
| 博客文章PDF | PDF格式 | 沒有 | |
| blogPost.pdf | pdf格式 | PDF格式 | 是 |
| blogPost.gif | gif | GIF | 是 |
| blogPost.jpg | jpg | JPEG格式 | 是 |
| blogPost.png | png | PNG | 是 |
| blogPostPDF.txt | 文本文件 | PDF格式 | 沒有 |
| blogPostPDF.xml | XML文件 | PDF格式 | 沒有 |
| blogPostPNG.gif | gif | PNG | 沒有 |
| blogPostPNG.jpg | jpg | PNG | 沒有 |
| ustin.txt | 文本文件 | 文本 | 是 |
| ustin.xml | XML文件 | 文本 | 沒有 |
| 塵土 | 文本 | 沒有 |
Files.probeContentType(Path)[JDK 7]
Java SE 7引入了高度實用的Files類 , 該類的Javadoc簡潔地描述了它的用法:“該類專門由對文件,目錄或其他類型的文件進行操作的靜態方法組成”,以及“在大多數情況下,此處定義的方法”將委派給關聯的文件系統提供者以執行文件操作。”
java.nio.file.Files類提供了方法probeContentType(Path),該方法通過使用“已安裝的FileTypeDetector實現”來“探測文件的內容類型”(Javadoc還指出,“ Java虛擬機的給定調用”維護系統范圍的文件類型檢測器列表”)。
/*** Identify file type of file with provided path and name* using JDK 7's Files.probeContentType(Path).** @param fileName Name of file whose type is desired.* @return String representing identified type of file with provided name.*/ public String identifyFileTypeUsingFilesProbeContentType(final String fileName) {String fileType = "Undetermined";final File file = new File(fileName);try{fileType = Files.probeContentType(file.toPath());}catch (IOException ioException){out.println("ERROR: Unable to determine file type for " + fileName+ " due to exception " + ioException);}return fileType; }對先前定義的文件集執行以上基于Files.probeContentType(Path)的方法時,輸出將顯示,如下一個屏幕快照所示。
屏幕快照表明我的JVM上Files.probeContentType(Path)的默認行為似乎與文件擴展名緊密相關。 沒有擴展名的文件的文件類型顯示為“ null”,其他列出的文件類型與文件的擴展名而不是其實際內容匹配。 例如,所有三個名稱都以“ dustin”開頭的文件實際上都是同一個單句文本文件,但是Files.probeContentType(Path)聲明它們都是不同的類型,并且列出的類型與不同的文件擴展名緊密相關。基本上是相同的文本文件。
MimetypesFileTypeMap.getContentType(String)[JDK 6]
Java SE 6引入了 MimetypesFileTypeMap類,以使用“ .mime.types格式”提供“通過文件擴展名進行文件的數據鍵入”。 該類的Javadoc解釋了該類在給定系統中的哪里查找MIME類型文件條目。 我的示例使用JDK 8安裝中提供的現成產品。 下一個代碼清單演示了javax.activation.MimetypesFileTypeMap用法。
/*** Identify file type of file with provided name using* JDK 6's MimetypesFileTypeMap.** See Javadoc documentation for MimetypesFileTypeMap class* (http://docs.oracle.com/javase/8/docs/api/javax/activation/MimetypesFileTypeMap.html)* for details on how to configure mapping of file types or extensions.*/ public String identifyFileTypeUsingMimetypesFileTypeMap(final String fileName) { final MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();return fileTypeMap.getContentType(fileName); }下一個屏幕快照展示了針對一組測試文件運行此示例的輸出。
此輸出表明MimetypesFileTypeMap方法為多個文件(包括XML文件和不帶.txt后綴的文本文件)返回application / octet-stream的MIME類型。 我們還看到,就像前面討論的方法一樣,這種方法在某些情況下使用文件的擴展名來確定文件類型,因此當該文件名與常規擴展名不同時,會錯誤地報告該文件的實際文件類型。
URLConnection.getContentType()
我將介紹URLConnection中支持文件類型檢測的三種方法。 第一個是URLConnection.getContentType() ,該方法“返回content-type標頭字段的值”。 下一個代碼清單中演示了此實例方法的使用,并且在代碼清單后顯示了針對通用測試文件運行該代碼的輸出。
/*** Identify file type of file with provided path and name* using JDK's URLConnection.getContentType().** @param fileName Name of file whose type is desired.* @return Type of file for which name was provided.*/ public String identifyFileTypeUsingUrlConnectionGetContentType(final String fileName) {String fileType = "Undetermined";try{final URL url = new URL("file://" + fileName);final URLConnection connection = url.openConnection();fileType = connection.getContentType();}catch (MalformedURLException badUrlEx){out.println("ERROR: Bad URL - " + badUrlEx);}catch (IOException ioEx){out.println("Cannot access URLConnection - " + ioEx);}return fileType; }
使用URLConnection.getContentType()的文件檢測方法與文件的擴展名(而不是實際的文件類型URLConnection.getContentType()高度相關。 如果沒有擴展名,則返回的字符串為“ content / unknown”。
URLConnection.guessContentTypeFromName(String)
我將在這里介紹的URLConnection提供的第二種文件檢測方法是其方法guessContentTypeFromName(String) 。 下一個代碼清單和相關的輸出屏幕快照中演示了此靜態方法的使用。
/*** Identify file type of file with provided path and name* using JDK's URLConnection.guessContentTypeFromName(String).** @param fileName Name of file whose type is desired.* @return Type of file for which name was provided.*/ public String identifyFileTypeUsingUrlConnectionGuessContentTypeFromName(final String fileName) {return URLConnection.guessContentTypeFromName(fileName); }
URLConnection的guessContentTypeFromName(String)文件檢測方法對沒有文件擴展名的文件顯示為“ null”,否則返回與文件擴展名緊密鏡像的文件類型字符串表示形式。 這些結果與前面顯示的Files.probeContentType(Path)方法提供的結果非常相似,一個顯著的區別是URLConnection的guessContentTypeFromName(String)方法將擴展名為.xml的文件標識為文件類型“ application / xml”而Files.probeContentType(Path)將這些相同的文件類型標識為“ text / xml”。
URLConnection.guessContentTypeFromStream(InputStream)
我介紹的URLConnection為文件類型檢測提供的第三種方法是通過類的靜態方法guessContentTypeFromStream(InputStream) 。 接下來顯示使用此方法的代碼清單以及屏幕快照中的相關輸出。
/*** Identify file type of file with provided path and name* using JDK's URLConnection.guessContentTypeFromStream(InputStream).** @param fileName Name of file whose type is desired.* @return Type of file for which name was provided.*/ public String identifyFileTypeUsingUrlConnectionGuessContentTypeFromStream(final String fileName) {String fileType;try{fileType = URLConnection.guessContentTypeFromStream(new FileInputStream(new File(fileName)));}catch (IOException ex){out.println("ERROR: Unable to process file type for " + fileName + " - " + ex);fileType = "null";}return fileType; }
所有文件類型均為空! Javadoc似乎對URLConnection.guessContentTypeFromStream(InputStream)方法的InputStream參數進行了解釋:“支持標記的輸入流。” 事實證明,在我的示例中, FileInputStream的實例不支持標記(它們對markSupported()的調用均返回false )。
阿帕奇·蒂卡(Apache Tika)
到目前為止,本文中涵蓋的所有文件檢測示例都是JDK提供的方法。 有些第三方庫也可用于檢測Java中的文件類型。 一個示例是Apache Tika ,它是一種“內容分析工具包”,它“可以從上千種不同的文件類型中檢測并提取元數據和文本。” 在本文中,我將研究如何使用Tika的Facade類及其detect(String)方法來檢測文件類型。 我展示的三個示例中的實例方法調用相同,但是結果不同,因為Tika Facade類的每個實例都使用不同的Detector實例化。
下代碼清單顯示了具有不同Detector的Tika實例的實例化。
/** Instance of Tika facade class with default configuration. */ private final Tika defaultTika = new Tika();/** Instance of Tika facade class with MimeTypes detector. */ private final Tika mimeTika = new Tika(new MimeTypes()); his is /** Instance of Tika facade class with Type detector. */ private final Tika typeTika = new Tika(new TypeDetector());通過用各自的Detector實例化Tika這三個實例,我們可以在每個實例上為測試文件集調用detect(String)方法。 接下來顯示此代碼。
/*** Identify file type of file with provided name using* Tika's default configuration.** @param fileName Name of file for which file type is desired.* @return Type of file for which file name was provided.*/ public String identifyFileTypeUsingDefaultTika(final String fileName) {return defaultTika.detect(fileName); }/*** Identify file type of file with provided name using* Tika's with a MimeTypes detector.** @param fileName Name of file for which file type is desired.* @return Type of file for which file name was provided.*/ public String identifyFileTypeUsingMimeTypesTika(final String fileName) {return mimeTika.detect(fileName); }/*** Identify file type of file with provided name using* Tika's with a Types detector.** @param fileName Name of file for which file type is desired.* @return Type of file for which file name was provided.*/ public String identifyFileTypeUsingTypeDetectorTika(final String fileName) {return typeTika.detect(fileName); }當對前面的示例中使用的同一組文件執行以上三個Tika檢測示例時,輸出將顯示,如下一個屏幕快照所示。
從輸出中我們可以看到,默認的Tika檢測器報告的文件類型類似于本文前面顯示的其他一些方法(與文件擴展名緊密相關)。 其他兩個演示過的檢測器指出,在大多數情況下,文件類型為application / octet-stream。 因為我調用了接受String的detect(-)的重載版本,所以文件類型檢測是“基于已知的文件擴展名”。
如果使用重載的detect(File)方法而不是detect(String) ,則標識的文件類型結果將比以前的Tika示例和以前的JDK示例好得多。 實際上,“假”擴展名不會使檢測器蒙上陰影,在我的示例中,默認的Tika檢測器在識別適當的文件類型方面尤其出色,即使該擴展名不是與該文件類型關聯的普通文件類型也是如此。 接下來顯示使用Tika.detect(File)的代碼和關聯的輸出。
/*** Identify file type of file with provided name using* Tika's default configuration.** @param fileName Name of file for which file type is desired.* @return Type of file for which file name was provided.*/public String identifyFileTypeUsingDefaultTikaForFile(final String fileName){String fileType;try{final File file = new File(fileName);fileType = defaultTika.detect(file);}catch (IOException ioEx){out.println("Unable to detect type of file " + fileName + " - " + ioEx);fileType = "Unknown";}return fileType;}/*** Identify file type of file with provided name using* Tika's with a MimeTypes detector.** @param fileName Name of file for which file type is desired.* @return Type of file for which file name was provided.*/public String identifyFileTypeUsingMimeTypesTikaForFile(final String fileName){String fileType;try{final File file = new File(fileName);fileType = mimeTika.detect(file);}catch (IOException ioEx){out.println("Unable to detect type of file " + fileName + " - " + ioEx);fileType = "Unknown";}return fileType;}/*** Identify file type of file with provided name using* Tika's with a Types detector.** @param fileName Name of file for which file type is desired.* @return Type of file for which file name was provided.*/public String identifyFileTypeUsingTypeDetectorTikaForFile(final String fileName){String fileType;try{final File file = new File(fileName);fileType = typeTika.detect(file);}catch (IOException ioEx){out.println("Unable to detect type of file " + fileName + " - " + ioEx);fileType = "Unknown";}return fileType;}
注意事項和自定義
文件類型檢測并不是一件容易的事。 本文中演示的Java文件檢測方法提供了文件檢測的基本方法,這些方法通常高度依賴于文件名的擴展名。 如果使用文件檢測方法可以識別的常規擴展名來命名文件,則這些方法通常就足夠了。 但是,如果使用非常規文件類型擴展名,或者該擴展名用于具有與該擴展名常規相關聯的文件之外的其他類型的文件,則這些文件檢測方法中的大多數會在沒有定制的情況下崩潰。 幸運的是,大多數方法都提供了自定義文件擴展名到文件類型的映射的能力。 在本文顯示的示例中,當擴展名不是特定文件類型的常規擴展名時,使用Tika.detect(File)的Tika方法通常是最準確的。
結論
在Java中,有許多機制可用于簡單文件類型檢測。 這篇文章回顧了一些用于文件檢測的標準JDK方法,以及一些使用Tika進行文件檢測的示例。
翻譯自: https://www.javacodegeeks.com/2015/02/determining-file-types-java.html
總結
以上是生活随笔為你收集整理的在Java中确定文件类型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓爬虫app(安卓pac)
- 下一篇: 投资能力备案怎么填(投资能力备案)