Способ первый: не заглядываем внутрь
Проще всего определить тип файла по его расширению. Знакомая с детства, понятная, быстрая и весьма неточная схема. Собственно, точность зависит от того, насколько полным и актуальным является используемый нами справочник расширений. Чтобы не хардкодить свой справочник используем, например javax.activation.MimetypesFileTypeMap:
import javax.activation.MimetypesFileTypeMap;
import java.io.File;
class GetMimeType {
public static void main(String args[]) {
File f = new File("gumby.gif");
System.out.println("Mime Type of " + f.getName() + " is " +
new MimetypesFileTypeMap().getContentType(f));
// expected output :
// "Mime Type of gumby.gif is image/gif"
}
}
Для работы этого кода потребуется подключить библиотеку activation.jar, которую можно взять отсюда.
Библиотека ищет данные о типе файла в нескольких местах системы в следующем порядке:
- Programmatically added entries to the MimetypesFileTypeMap instance.
- The file .mime.types in the user's home directory.
- The file
/lib/mime.types. - The file or resources named META-INF/mime.types.
- The file or resource named META-INF/mimetypes.default (usually found only in the activation.jar file).
Способ более надёжный, не требует дополнительных библиотек, но не рекомендуется к использованию в "промышленных масштабах" ввиду крайней медлительности.
import java.net.*;
public class FileUtils{
public static String getMimeType(String fileUrl)
throws java.io.IOException, MalformedURLException
{
String type = null;
URL u = new URL(fileUrl);
URLConnection uc = null;
uc = u.openConnection();
type = uc.getContentType();
return type;
}
public static void main(String args[]) throws Exception {
System.out.println(FileUtils.getMimeType("file://c:/temp/test.TXT"));
// output : text/plain
}
}
Тут мы практически открываем соединение с файлом по протоколу file:// и читаем заголовок content-type из полученного соединения.
Чуть более быстрый способ:
import java.net.FileNameMap;
import java.net.URLConnection;
public class FileUtils {
public static String getMimeType(String fileUrl)
throws java.io.IOException
{
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String type = fileNameMap.getContentTypeFor(fileUrl);
return type;
}
public static void main(String args[]) throws Exception {
System.out.println(FileUtils.getMimeType("file://c:/temp/test.TXT"));
// output : text/plain
}
}
Принцип тут тот же.Способ третий: Посмотрим-таки внутрь!
Самый надёжный способ, определяющий тип файла по его содержимому. Точен настолько, насколько это возможно, достаточно быстр. Но требует использования большого числа сторонних библиотек. Например, используя Apache Tika:
import java.io.File;
import java.io.FileInputStream;
import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.AutoDetectParser;
import org.apache.tika.parser.Parser;
import org.apache.tika.sax.BodyContentHandler;
import org.xml.sax.ContentHandler;
public class Main {
public static void main(String args[]) throws Exception {
FileInputStream is = null;
try {
File f = new File("C:/Temp/mime/test.docx");
is = new FileInputStream(f);
ContentHandler contenthandler = new BodyContentHandler();
Metadata metadata = new Metadata();
metadata.set(Metadata.RESOURCE_NAME_KEY, f.getName());
Parser parser = new AutoDetectParser();
// OOXMLParser parser = new OOXMLParser();
parser.parse(is, contenthandler, metadata);
System.out.println("Mime: " + metadata.get(Metadata.CONTENT_TYPE));
System.out.println("Title: " + metadata.get(Metadata.TITLE));
System.out.println("Author: " + metadata.get(Metadata.AUTHOR));
System.out.println("content: " + contenthandler.toString());
}
catch (Exception e) {
e.printStackTrace();
}
finally {
if (is != null) is.close();
}
}
}
Библиотека - часть поискового движка Lucene - подключает в рантайме около 20 (!) зависимостей (в общей сложности мегабайт на 18). Смотрите сами, нужно ли оно вам в проекте.Более компактный вариант - использовать библиотеку JMimeMagic:
public static String getMime(String path) {
MagicMatch match = null;
try {
match = Magic.getMagicMatch(new File(path), true);
} catch (Exception e){
e.printStackTrace(System.err);
}
return match.getMimeType();
}
Плюсы: всего две зависимости: Apache Common logging и Jakarta Oro (уже не разрабатывается). Вместе с зависимостями размер библиотеки едва превышает 150 Kb.Минусы: сравнительно невысокая точность - "не узнаёт" несколько популярных форматов файлов, иногда "убивает" наше приложение с ошибкой OutOfMemoryError. На исправление ошибок вряд ли стоит рассчитывать: последняя версия вышла в 2006 году.
...или библиотеку Mime-Util:
import eu.medsea.mimeutil.MimeUtil;
public class Main {
public static void main(String[] args) {
MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
File f = new File ("c:/temp/mime/test.doc");
Collection<?> mimeTypes = MimeUtil.getMimeTypes(f);
System.out.println(mimeTypes);
// output : application/msword
}
}
Минусы: несколько больший размер, есть проблема с "узнаванием" текстовых файлов: все они (включая html) воспринимаются как "application/octet-stream". Плюсы: достаточно высокая точность определения типов, всего одна зависимость (SLF4J), более стабильная работа.Как правило, более "навороченные" библиотеки, распознающие больше форматов соответственно и "тяжелее". Я уверен, что есть ещё достаточно много библиотек, не описанных в статье, вольный перевод которой я тут попытался представить вашему вниманию. Если у кого-нибудь возникнет желание познакомиться с какой-нибудь подробнее, дайте ссылку в комментариях, я с удовольствием посмотрю на неё и опишу результат знакомства.
http://devcolibri.com
ОтветитьУдалитьhttp://devcolibri.com
ОтветитьУдалитьhttp://dorian-gray.ru/
ОтветитьУдалить