Получение Mime-типа файла в Java
Мне просто интересно, как большинство людей выбирают MIME-тип из файла на Java? Пока что я попробовал два утилиты: JMimeMagic
& Mime-Util
,
Первый дал мне исключения памяти, второй не закрывает свои потоки должным образом. Мне просто интересно, есть ли у кого-то еще метод / библиотека, которые они использовали и работали правильно?
29 ответов
В Java 7 теперь вы можете просто использовать Files.probeContentType(path)
,
К несчастью,
mimeType = file.toURL().openConnection().getContentType();
не работает, так как это использование URL оставляет файл заблокированным, так что, например, его невозможно восстановить.
Тем не менее, у вас есть это:
mimeType= URLConnection.guessContentTypeFromName(file.getName());
а также следующее, которое имеет преимущество в том, что оно выходит за рамки простого использования расширения файла и позволяет взглянуть на контент
InputStream is = new BufferedInputStream(new FileInputStream(file));
mimeType = URLConnection.guessContentTypeFromStream(is);
//...close stream
Однако, как следует из приведенного выше комментария, встроенная таблица типов mime довольно ограничена, не включая, например, MSWord и PDF. Итак, если вы хотите обобщить, вам нужно выйти за пределы встроенных библиотек, используя, например, Mime-Util (отличная библиотека, использующая как расширение файла, так и контент).
С Apache Tika вам нужно всего три строчки кода:
File file = new File("/path/to/file");
Tika tika = new Tika();
System.out.println(tika.detect(file));
Если у вас отличная консоль, просто вставьте и запустите этот код, чтобы поиграть с ней:
@Grab('org.apache.tika:tika-core:1.14')
import org.apache.tika.Tika;
def tika = new Tika()
def file = new File("/path/to/file")
println tika.detect(file)
Имейте в виду, что его API богаты, он может анализировать "что угодно". Начиная с версии 1.14, у вас есть:
String detect(byte[] prefix)
String detect(byte[] prefix, String name)
String detect(File file)
String detect(InputStream stream)
String detect(InputStream stream, Metadata metadata)
String detect(InputStream stream, String name)
String detect(Path path)
String detect(String name)
String detect(URL url)
Смотрите apidocs для получения дополнительной информации.
JAF API является частью JDK 6. Посмотрите на javax.activation
пакет.
Самые интересные занятия javax.activation.MimeType
- фактический держатель типа MIME - и javax.activation.MimetypesFileTypeMap
- класс, экземпляр которого может разрешить MIME-тип как String для файла:
String fileName = "/path/to/file";
MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap();
// only by file name
String mimeType = mimeTypesMap.getContentType(fileName);
// or by actual File instance
File file = new File(fileName);
mimeType = mimeTypesMap.getContentType(file);
Apache Tika предлагает в tika-core обнаружение типа пантомимы, основанное на магических маркерах в префиксе потока. tika-core
не извлекает другие зависимости, что делает его таким же легким, как в настоящее время не поддерживаемая утилита обнаружения Mime-типов.
Простой пример кода (Java 7) с использованием переменных theInputStream
а также theFileName
try (InputStream is = theInputStream;
BufferedInputStream bis = new BufferedInputStream(is);) {
AutoDetectParser parser = new AutoDetectParser();
Detector detector = parser.getDetector();
Metadata md = new Metadata();
md.add(Metadata.RESOURCE_NAME_KEY, theFileName);
MediaType mediaType = detector.detect(bis, md);
return mediaType.toString();
}
Обратите внимание, что MediaType.detect(...) нельзя использовать напрямую ( TIKA-1120). Дополнительные советы предоставляются по адресу https://tika.apache.org/0.10/detection.html.
Если вы разработчик Android, вы можете использовать служебный класс android.webkit.MimeTypeMap
который сопоставляет MIME-типы с расширениями файлов и наоборот.
Следующий фрагмент кода может помочь вам.
private static String getMimeType(String fileUrl) {
String extension = MimeTypeMap.getFileExtensionFromUrl(fileUrl);
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
Из розеиндии:
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mimeType = fileNameMap.getContentTypeFor("alert.gif");
Мне просто интересно, как большинство людей выбирают MIME-тип из файла на Java?
Я опубликовал свой пакет Java SimpleMagic, который позволяет определять тип содержимого (mime-type) из файлов и байтовых массивов. Он предназначен для чтения и запуска магических файлов команд Unix file(1), которые являются частью большинства конфигураций ОС Unix.
Я попробовал Apache Tika, но он огромен с кучей зависимостей, URLConnection
не использует байты файлов, и MimetypesFileTypeMap
также просто смотрит на имена файлов.
С SimpleMagic вы можете сделать что-то вроде:
// create a magic utility using the internal magic file
ContentInfoUtil util = new ContentInfoUtil();
// if you want to use a different config file(s), you can load them by hand:
// ContentInfoUtil util = new ContentInfoUtil("/etc/magic");
...
ContentInfo info = util.findMatch("/tmp/upload.tmp");
// or
ContentInfo info = util.findMatch(inputStream);
// or
ContentInfo info = util.findMatch(contentByteArray);
// null if no match
if (info != null) {
String mimeType = info.getMimeType();
}
Если вы застряли с Java 5-6, то этот служебный класс из серво продукта с открытым исходным кодом.
Вам нужна только эта функция
public static String getContentType(byte[] data, String name)
Он проверяет первые байты содержимого и возвращает типы содержимого на основе этого содержимого, а не по расширению файла.
Чтобы скинуть мои 5 центов:
TL,DR
Я использую MimetypesFileTypeMap и добавляю в файл mime.types любой mime, которого там нет, и он мне особенно нужен.
А теперь долго читал:
Прежде всего, список типов MIME огромен, см. Здесь: https://www.iana.org/assignments/media-types/media-types.xhtml
Мне нравится сначала использовать стандартные возможности, предоставляемые JDK, и если это не сработает, я пойду и поищу что-нибудь еще.
Определить тип файла по расширению файла
Начиная с 1.6, Java имеет MimetypesFileTypeMap, как указано в одном из ответов выше, и это самый простой способ определить тип mime:
new MimetypesFileTypeMap().getContentType( fileName );
В его ванильной реализации это мало что делает (т.е. работает для.html, но не для.png). Однако очень просто добавить любой тип контента, который вам может понадобиться:
- Создайте файл с именем "mime.types" в папке META-INF в вашем проекте
- Добавьте строку для каждого типа MIME, который вам нужен, и реализация по умолчанию не обеспечивает (существуют сотни типов MIME, и список увеличивается с течением времени).
Пример записи для файлов png и js:
image/png png PNG
application/javascript js
Подробнее о формате файла mime.types см. Здесь: https://docs.oracle.com/javase/7/docs/api/javax/activation/MimetypesFileTypeMap.html
Определить тип файла по содержимому файла
Начиная с версии 1.7, Java имеет java.nio.file.spi.FileTypeDetector, который определяет стандартный API для определения типа файла специфичным для реализации способом.
Чтобы получить MIME-тип для файла, вы просто должны использовать Files и сделать это в своем коде:
Files.probeContentType(Paths.get("either file name or full path goes here"));
Определение API предоставляет средства, которые поддерживают либо определение типа mime файла по имени файла, либо по содержимому файла (магические байты). Вот почему метод probeContentType() выдает IOException, если реализация этого API использует предоставленный ему Path, чтобы фактически попытаться открыть связанный с ним файл.
Опять же, ванильная реализация этого (того, что идет с JDK) оставляет желать лучшего.
В каком-то идеальном мире в далекой-далекой галактике все эти библиотеки, которые пытаются решить эту проблему типа "файл-пантомима", просто реализуют java.nio.file.spi.FileTypeDetector, вы можете оставить jar-файл предпочтительной библиотеки реализации. файл в ваш путь к классу, и это было бы так.
В реальном мире, где вам нужен раздел TL,DR, вы должны найти библиотеку с большинством звездочек рядом с ее именем и использовать ее. Для этого конкретного случая мне не нужен (пока;)).
Простой и лучший вариант - получить тип MIME содержимого из местоположения файла.
Используйте этот импорт
import java.nio.file.Files;
import java.nio.file.Path;
Код
String type = Files.probeContentType(Path.of(imagePath));
Я попробовал несколько способов сделать это, включая первый, который сказал @Joshua Fox. Но некоторые не распознают частые mimetypes, как для файлов PDF, а другие не могут быть надежными с поддельными файлами (я пробовал с файлом RAR с расширением, измененным на TIF). Решение, которое я нашел, как также говорит @Joshua Fox поверхностно, заключается в использовании MimeUtil2, например так:
MimeUtil2 mimeUtil = new MimeUtil2();
mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
String mimeType = MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file)).toString();
Апач Тика.
<!-- https://mvnrepository.com/artifact/org.apache.tika/tika-parsers -->
<dependency>
<groupId>org.apache.tika</groupId>
<artifactId>tika-parsers</artifactId>
<version>1.24</version>
</dependency>
и две строки кода.
Tika tika=new Tika();
tika.detect(inputStream);
Снимок экрана ниже
Если вы работаете с сервлетом и вам доступен контекст сервлета, вы можете использовать:
getServletContext().getMimeType( fileName );
Это самый простой способ, который я нашел для этого:
byte[] byteArray = ...
InputStream is = new BufferedInputStream(new ByteArrayInputStream(byteArray));
String mimeType = URLConnection.guessContentTypeFromStream(is);
Вы можете сделать это только одной строкой: MimetypesFileTypeMap (). GetContentType (new File ("filename.ext")). Посмотрите полный тестовый код (Java 7):
import java.io.File;
import javax.activation.MimetypesFileTypeMap;
public class MimeTest {
public static void main(String a[]){
System.out.println(new MimetypesFileTypeMap().getContentType(
new File("/path/filename.txt")));
}
}
Этот код производит следующий вывод: text / plain
Лучше использовать двухслойную проверку для загрузки файлов.
Сначала вы можете проверить mimeType и проверить его.
Во-вторых, вы должны преобразовать первые 4 байта вашего файла в шестнадцатеричное, а затем сравнить его с магическими числами. Тогда это будет действительно безопасный способ проверки файлов.
Я не мог найти ничего для проверки
video/mp4
Тип MIME, поэтому я сделал собственное решение. Я случайно заметил, что Википедия ошибалась и что
00 00 00 18 66 74 79 70 69 73 6F 6D
подпись файла неверна. четвертый байт (18
) и все
70
(исключено) после изменений довольно много среди других действительных
mp4
файлы.
Этот код по сути является копией / вставкой
URLConnection.guessContentTypeFromStream
код, но адаптированный к
video/mp4
.
BufferedInputStream bis = new BufferedInputStream(new ByteArrayInputStream(content));
String mimeType = URLConnection.guessContentTypeFromStream(bis);
// Goes full barbaric and processes the bytes manually
if (mimeType == null){
// These ints converted in hex ar:
// 00 00 00 18 66 74 79 70 69 73 6F 6D
// which are the file signature (magic bytes) for .mp4 files
// from https://www.wikiwand.com/en/List_of_file_signatures
// just ctrl+f "mp4"
int[] mp4_sig = {0, 0, 0, 24, 102, 116, 121, 112};
bis.reset();
bis.mark(16);
int[] firstBytes = new int[8];
for (int i = 0; i < 8; i++) {
firstBytes[i] = bis.read();
}
// This byte doesn't matter for the file signature and changes
mp4_sig[3] = content[3];
bis.reset();
if (Arrays.equals(firstBytes, mp4_sig)){
mimeType = "video/mp4";
}
}
Успешно протестирован против 10 различных
.mp4
файлы.
РЕДАКТИРОВАТЬ: Вот полезная ссылка (если она все еще в сети), где вы можете найти образцы многих типов. У меня нет этих видео, и я тоже не знаю, у кого они есть, но они полезны для тестирования приведенного выше кода.
Собственно, детектор Apache Tika
Tika.detect(File)
лучший вариант и более точный, чем
Files.probeContentType(path)
.
ознакомьтесь с этим отличным кратким справочником, который содержит примеры и образцы кода.
Решение для определения типа файла 1 состоит из следующих частей:
- Список подписей файлов (см список Кесслера , список Википедии , а также список Space Создателя )
- Список типов носителей
- Карта типов мультимедиа с расширениями имен файлов
- Сравнение подписей файлов с
File
,Path
, или жеInputStream
источники данных
Не забудьте указать кредит при копировании кода.
StreamMediaType.java
В следующем коде
-1
означает пропустить сравнение байта по этому индексу; а
-2
обозначает конец сигнатуры типа файла. Это обнаруживает двоичные форматы, в первую очередь изображения, и несколько вариантов формата простого текста (HTML, SVG, XML). Код использует до первых 11 «магических» байтов заголовка источника данных. Приветствуются оптимизации и улучшения, сокращающие логику.
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.Map;
import static com.keenwrite.io.MediaType.*;
import static java.lang.System.arraycopy;
public class StreamMediaType {
private static final int FORMAT_LENGTH = 11;
private static final int END_OF_DATA = -2;
private static final Map<int[], MediaType> FORMAT = new LinkedHashMap<>();
static {
//@formatter:off
FORMAT.put( ints( 0x3C, 0x73, 0x76, 0x67, 0x20 ), IMAGE_SVG_XML );
FORMAT.put( ints( 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ), IMAGE_PNG );
FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xE0 ), IMAGE_JPEG );
FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xEE ), IMAGE_JPEG );
FORMAT.put( ints( 0xFF, 0xD8, 0xFF, 0xE1, -1, -1, 0x45, 0x78, 0x69, 0x66, 0x00 ), IMAGE_JPEG );
FORMAT.put( ints( 0x49, 0x49, 0x2A, 0x00 ), IMAGE_TIFF );
FORMAT.put( ints( 0x4D, 0x4D, 0x00, 0x2A ), IMAGE_TIFF );
FORMAT.put( ints( 0x47, 0x49, 0x46, 0x38 ), IMAGE_GIF );
FORMAT.put( ints( 0x8A, 0x4D, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A ), VIDEO_MNG );
FORMAT.put( ints( 0x25, 0x50, 0x44, 0x46, 0x2D, 0x31, 0x2E ), APP_PDF );
FORMAT.put( ints( 0x38, 0x42, 0x50, 0x53, 0x00, 0x01 ), IMAGE_PHOTOSHOP );
FORMAT.put( ints( 0x25, 0x21, 0x50, 0x53, 0x2D, 0x41, 0x64, 0x6F, 0x62, 0x65, 0x2D ), APP_EPS );
FORMAT.put( ints( 0x25, 0x21, 0x50, 0x53 ), APP_PS );
FORMAT.put( ints( 0xFF, 0xFB, 0x30 ), AUDIO_MP3 );
FORMAT.put( ints( 0x49, 0x44, 0x33 ), AUDIO_MP3 );
FORMAT.put( ints( 0x3C, 0x21 ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x68, 0x74, 0x6D, 0x6C ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x68, 0x65, 0x61, 0x64 ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x62, 0x6F, 0x64, 0x79 ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x48, 0x54, 0x4D, 0x4C ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x48, 0x45, 0x41, 0x44 ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x42, 0x4F, 0x44, 0x59 ), TEXT_HTML );
FORMAT.put( ints( 0x3C, 0x3F, 0x78, 0x6D, 0x6C, 0x20 ), TEXT_XML );
FORMAT.put( ints( 0xFE, 0xFF, 0x00, 0x3C, 0x00, 0x3f, 0x00, 0x78 ), TEXT_XML );
FORMAT.put( ints( 0xFF, 0xFE, 0x3C, 0x00, 0x3F, 0x00, 0x78, 0x00 ), TEXT_XML );
FORMAT.put( ints( 0x42, 0x4D ), IMAGE_BMP );
FORMAT.put( ints( 0x23, 0x64, 0x65, 0x66 ), IMAGE_X_BITMAP );
FORMAT.put( ints( 0x21, 0x20, 0x58, 0x50, 0x4D, 0x32 ), IMAGE_X_PIXMAP );
FORMAT.put( ints( 0x2E, 0x73, 0x6E, 0x64 ), AUDIO_BASIC );
FORMAT.put( ints( 0x64, 0x6E, 0x73, 0x2E ), AUDIO_BASIC );
FORMAT.put( ints( 0x52, 0x49, 0x46, 0x46 ), AUDIO_WAV );
FORMAT.put( ints( 0x50, 0x4B ), APP_ZIP );
FORMAT.put( ints( 0x41, 0x43, -1, -1, -1, -1, 0x00, 0x00, 0x00, 0x00, 0x00 ), APP_ACAD );
FORMAT.put( ints( 0xCA, 0xFE, 0xBA, 0xBE ), APP_JAVA );
FORMAT.put( ints( 0xAC, 0xED ), APP_JAVA_OBJECT );
//@formatter:on
}
private StreamMediaType() {
}
public static MediaType getMediaType( final Path path ) throws IOException {
return getMediaType( path.toFile() );
}
public static MediaType getMediaType( final java.io.File file )
throws IOException {
try( final var fis = new FileInputStream( file ) ) {
return getMediaType( fis );
}
}
public static MediaType getMediaType( final InputStream is )
throws IOException {
final var input = new byte[ FORMAT_LENGTH ];
final var count = is.read( input, 0, FORMAT_LENGTH );
if( count > 1 ) {
final var available = new byte[ count ];
arraycopy( input, 0, available, 0, count );
return getMediaType( available );
}
return UNDEFINED;
}
public static MediaType getMediaType( final byte[] source ) {
assert source != null;
final var header = new int[]{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
for( int i = 0; i < source.length; i++ ) {
header[ i ] = source[ i ] & 0xFF;
}
for( final var key : FORMAT.keySet() ) {
int i = -1;
boolean matches = true;
while( ++i < FORMAT_LENGTH && key[ i ] != END_OF_DATA && matches ) {
matches = key[ i ] == header[ i ];
}
if( matches ) {
return FORMAT.get( key );
}
}
return UNDEFINED;
}
private static int[] ints( final int... data ) {
final var magic = new int[ FORMAT_LENGTH ];
int i = -1;
while( ++i < data.length ) {
magic[ i ] = data[ i ];
}
while( i < FORMAT_LENGTH ) {
magic[ i++ ] = END_OF_DATA;
}
return magic;
}
}
MediaType.java
Определите форматы файлов в соответствии со списком носителятипов носителей IANA . Обратите внимание, что расширения имен файлов отображаются в
MediaTypeExtension
. Существует зависимость от класса Apache FilenameUtils для его
getExtension
функция.
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import static MediaType.TypeName.*;
import static MediaTypeExtension.getMediaType;
import static org.apache.commons.io.FilenameUtils.getExtension;
public enum MediaType {
APP_ACAD( APPLICATION, "acad" ),
APP_JAVA_OBJECT( APPLICATION, "x-java-serialized-object" ),
APP_JAVA( APPLICATION, "java" ),
APP_PS( APPLICATION, "postscript" ),
APP_EPS( APPLICATION, "eps" ),
APP_PDF( APPLICATION, "pdf" ),
APP_ZIP( APPLICATION, "zip" ),
FONT_OTF( "otf" ),
FONT_TTF( "ttf" ),
IMAGE_APNG( "apng" ),
IMAGE_ACES( "aces" ),
IMAGE_AVCI( "avci" ),
IMAGE_AVCS( "avcs" ),
IMAGE_BMP( "bmp" ),
IMAGE_CGM( "cgm" ),
IMAGE_DICOM_RLE( "dicom_rle" ),
IMAGE_EMF( "emf" ),
IMAGE_EXAMPLE( "example" ),
IMAGE_FITS( "fits" ),
IMAGE_G3FAX( "g3fax" ),
IMAGE_GIF( "gif" ),
IMAGE_HEIC( "heic" ),
IMAGE_HEIF( "heif" ),
IMAGE_HEJ2K( "hej2k" ),
IMAGE_HSJ2( "hsj2" ),
IMAGE_X_ICON( "x-icon" ),
IMAGE_JLS( "jls" ),
IMAGE_JP2( "jp2" ),
IMAGE_JPEG( "jpeg" ),
IMAGE_JPH( "jph" ),
IMAGE_JPHC( "jphc" ),
IMAGE_JPM( "jpm" ),
IMAGE_JPX( "jpx" ),
IMAGE_JXR( "jxr" ),
IMAGE_JXRA( "jxrA" ),
IMAGE_JXRS( "jxrS" ),
IMAGE_JXS( "jxs" ),
IMAGE_JXSC( "jxsc" ),
IMAGE_JXSI( "jxsi" ),
IMAGE_JXSS( "jxss" ),
IMAGE_KTX( "ktx" ),
IMAGE_KTX2( "ktx2" ),
IMAGE_NAPLPS( "naplps" ),
IMAGE_PNG( "png" ),
IMAGE_PHOTOSHOP( "photoshop" ),
IMAGE_SVG_XML( "svg+xml" ),
IMAGE_T38( "t38" ),
IMAGE_TIFF( "tiff" ),
IMAGE_WEBP( "webp" ),
IMAGE_WMF( "wmf" ),
IMAGE_X_BITMAP( "x-xbitmap" ),
IMAGE_X_PIXMAP( "x-xpixmap" ),
AUDIO_BASIC( AUDIO, "basic" ),
AUDIO_MP3( AUDIO, "mp3" ),
AUDIO_WAV( AUDIO, "x-wav" ),
VIDEO_MNG( VIDEO, "x-mng" ),
TEXT_HTML( TEXT, "html" ),
TEXT_MARKDOWN( TEXT, "markdown" ),
TEXT_PLAIN( TEXT, "plain" ),
TEXT_XHTML( TEXT, "xhtml+xml" ),
TEXT_XML( TEXT, "xml" ),
TEXT_YAML( TEXT, "yaml" ),
/*
* When all other lights go out.
*/
UNDEFINED( TypeName.UNDEFINED, "undefined" );
public enum TypeName {
APPLICATION,
AUDIO,
IMAGE,
TEXT,
UNDEFINED,
VIDEO
}
private final String mMediaType;
private final TypeName mTypeName;
private final String mSubtype;
MediaType( final String subtype ) {
this( IMAGE, subtype );
}
MediaType( final TypeName typeName, final String subtype ) {
mTypeName = typeName;
mSubtype = subtype;
mMediaType = typeName.toString().toLowerCase() + '/' + subtype;
}
public static MediaType valueFrom( final File file ) {
assert file != null;
return fromFilename( file.getName() );
}
public static MediaType fromFilename( final String filename ) {
assert filename != null;
return getMediaType( getExtension( filename ) );
}
public static MediaType valueFrom( final Path path ) {
assert path != null;
return valueFrom( path.toFile() );
}
public static MediaType valueFrom( String contentType ) {
if( contentType == null || contentType.isBlank() ) {
return UNDEFINED;
}
var i = contentType.indexOf( ';' );
contentType = contentType.substring(
0, i == -1 ? contentType.length() : i );
i = contentType.indexOf( '/' );
i = i == -1 ? contentType.length() : i;
final var type = contentType.substring( 0, i );
final var subtype = contentType.substring( i + 1 );
return valueFrom( type, subtype );
}
public static MediaType valueFrom(
final String type, final String subtype ) {
assert type != null;
assert subtype != null;
for( final var mediaType : values() ) {
if( mediaType.equals( type, subtype ) ) {
return mediaType;
}
}
return UNDEFINED;
}
public boolean equals( final String type, final String subtype ) {
assert type != null;
assert subtype != null;
return mTypeName.name().equalsIgnoreCase( type ) &&
mSubtype.equalsIgnoreCase( subtype );
}
public boolean isType( final TypeName typeName ) {
return mTypeName == typeName;
}
public String getSubtype() {
return mSubtype;
}
@Override
public String toString() {
return mMediaType;
}
}
MediaTypeExtension.java
Последний кусок головоломки - это карта
MediaType
s в их известные и распространенные / популярные расширения имен файлов. Это позволяет осуществлять двунаправленный поиск на основе расширений имен файлов.
import static MediaType.*;
import static java.util.List.of;
public enum MediaTypeExtension {
MEDIA_APP_ACAD( APP_ACAD, of( "dwg" ) ),
MEDIA_APP_PDF( APP_PDF ),
MEDIA_APP_PS( APP_PS, of( "ps" ) ),
MEDIA_APP_EPS( APP_EPS ),
MEDIA_APP_ZIP( APP_ZIP ),
MEDIA_AUDIO_MP3( AUDIO_MP3 ),
MEDIA_AUDIO_BASIC( AUDIO_BASIC, of( "au" ) ),
MEDIA_AUDIO_WAV( AUDIO_WAV, of( "wav" ) ),
MEDIA_FONT_OTF( FONT_OTF ),
MEDIA_FONT_TTF( FONT_TTF ),
MEDIA_IMAGE_APNG( IMAGE_APNG ),
MEDIA_IMAGE_BMP( IMAGE_BMP ),
MEDIA_IMAGE_GIF( IMAGE_GIF ),
MEDIA_IMAGE_JPEG( IMAGE_JPEG,
of( "jpg", "jpe", "jpeg", "jfif", "pjpeg", "pjp" ) ),
MEDIA_IMAGE_PNG( IMAGE_PNG ),
MEDIA_IMAGE_PSD( IMAGE_PHOTOSHOP, of( "psd" ) ),
MEDIA_IMAGE_SVG( IMAGE_SVG_XML, of( "svg" ) ),
MEDIA_IMAGE_TIFF( IMAGE_TIFF, of( "tiff", "tif" ) ),
MEDIA_IMAGE_WEBP( IMAGE_WEBP ),
MEDIA_IMAGE_X_BITMAP( IMAGE_X_BITMAP, of( "xbm" ) ),
MEDIA_IMAGE_X_PIXMAP( IMAGE_X_PIXMAP, of( "xpm" ) ),
MEDIA_VIDEO_MNG( VIDEO_MNG, of( "mng" ) ),
MEDIA_TEXT_MARKDOWN( TEXT_MARKDOWN, of(
"md", "markdown", "mdown", "mdtxt", "mdtext", "mdwn", "mkd", "mkdown",
"mkdn" ) ),
MEDIA_TEXT_PLAIN( TEXT_PLAIN, of( "txt", "asc", "ascii", "text", "utxt" ) ),
MEDIA_TEXT_R_MARKDOWN( TEXT_R_MARKDOWN, of( "Rmd" ) ),
MEDIA_TEXT_R_XML( TEXT_R_XML, of( "Rxml" ) ),
MEDIA_TEXT_XHTML( TEXT_XHTML, of( "xhtml" ) ),
MEDIA_TEXT_XML( TEXT_XML ),
MEDIA_TEXT_YAML( TEXT_YAML, of( "yaml", "yml" ) ),
MEDIA_UNDEFINED( UNDEFINED, of( "undefined" ) );
private final MediaType mMediaType;
private final List<String> mExtensions;
MediaTypeExtension( final MediaType mediaType ) {
this( mediaType, of( mediaType.getSubtype() ) );
}
MediaTypeExtension(
final MediaType mediaType, final List<String> extensions ) {
assert mediaType != null;
assert extensions != null;
assert !extensions.isEmpty();
mMediaType = mediaType;
mExtensions = extensions;
}
public String getExtension() {
return mExtensions.get( 0 );
}
public static MediaTypeExtension valueFrom( final MediaType mediaType ) {
for( final var type : values() ) {
if( type.isMediaType( mediaType ) ) {
return type;
}
}
return MEDIA_UNDEFINED;
}
boolean isMediaType( final MediaType mediaType ) {
return mMediaType == mediaType;
}
static MediaType getMediaType( final String extension ) {
final var sanitized = sanitize( extension );
for( final var mediaType : MediaTypeExtension.values() ) {
if( mediaType.isType( sanitized ) ) {
return mediaType.getMediaType();
}
}
return UNDEFINED;
}
private boolean isType( final String sanitized ) {
for( final var extension : mExtensions ) {
if( extension.equalsIgnoreCase( sanitized ) ) {
return true;
}
}
return false;
}
private static String sanitize( final String extension ) {
return extension == null ? "" : extension.toLowerCase();
}
private MediaType getMediaType() {
return mMediaType;
}
}
Использование:
// EXAMPLE -- Detect media type
//
final File image = new File( "filename.jpg" );
final MediaType mt = StreamMediaType.getMediaType( image );
// Tricky! The JPG could be a PNG in disguise.
if( mt.isType( MediaType.TypeName.IMAGE ) ) {
if( mt == MediaType.IMAGE_PNG ) {
// Nice try! Sneaky sneak.
}
}
// EXAMPLE -- Get typical media type file name extension
//
final String ext = MediaTypeExtension.valueFrom( MediaType.IMAGE_SVG_XML ).getExtension();
// EXAMPLE -- Get media type from HTTP request
//
final var url = new URL( "https://localhost/path/file.ext" );
final var conn = (HttpURLConnection) url.openConnection();
final var contentType = conn.getContentType();
MediaType mediaType = valueFrom( contentType );
// Fall back to stream detection probe
if( mediaType == UNDEFINED ) {
mediaType = StreamMediaType.getMediaType( conn.getInputStream() );
}
conn.disconnect();
Вы уловили идею.
Краткий обзор библиотеки:
- Apache Tika - раздувание 600 КБ, требуется несколько строк для настройки и несколько файлов JAR.
- jMimeMagic - Незавершенный, для настройки требуется несколько строк.
- MimeUtil2 - Достаточно большой, не работал "из коробки".
- - в комплекте с JDK, более глючный, чем лес, зараженный горными сосновыми жуками.
- FileTypeDetectorFiles.probeContentType - обнаружение зависит от платформы и считается ненадежным (источник ).
- MimetypesFileTypeMap - в комплекте с Activation.jar, использует расширение имени файла.
Примеры файлов аудио, видео и изображений для тестирования:
- http://mirrors.standaloneinstaller.com/video-sample/
- https://www.w3.org/People/mimasa/test/imgformat/
1 Термин "MIME-тип" не рекомендуется.
Весной файл MultipartFile;
org.springframework.web.multipart.MultipartFile
file.getContentType();
Если вы работаете на ОС Linux, есть командная строка file --mimetype
:
String mimetype(file){
//1. run cmd
Object cmd=Runtime.getRuntime().exec("file --mime-type "+file);
//2 get output of cmd , then
//3. parse mimetype
if(output){return output.split(":")[1].trim(); }
return "";
}
затем
mimetype("/home/nyapp.war") // 'application/zip'
mimetype("/var/www/ggg/au.mp3") // 'audio/mp3'
в Java у класса URLConnection есть метод, называемый угадыватьContentTypeFromName(String fileName), который можно использовать для угадывания типа мультимедиа MIME (также известного как тип содержимого) файла на основе его имени файла. Метод использует расширение имени файла для определения типа содержимого.
String fileName = "image.jpg";
String contentType = URLConnection.guessContentTypeFromName(fileName);
System.out.println(contentType); // "image/jpeg"
Если вам нужен надежный (т.е. согласованный) способ сопоставления расширений файлов с mime-типами, вот что я использую:
Он включает связанную базу данных типов mime и в основном инвертирует логику класса MimetypesFileTypeMap javax.activation, используя базу данных для инициализации «программных» записей. Таким образом, типы, определенные библиотекой, всегда имеют приоритет над тем, что может быть определено в разделенных ресурсах.
Проверьте магические байты потока или файла:
https://stackoverflow.com/a/65667558/3225638
Он использует чистую Java, но требует, чтобы вы определили
enum
типов, которые вы хотите обнаружить.
File file = new File(PropertiesReader.FILE_PATH);
MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
String mimeType = fileTypeMap.getContentType(file);
URLConnection uconnection = file.toURL().openConnection();
mimeType = uconnection.getContentType();
Попробовав другие библиотеки, я остановился на mime-util.
<groupId>eu.medsea.mimeutil</groupId>
<artifactId>mime-util</artifactId>
<version>2.1.3</version>
</dependency>
File file = new File("D:/test.tif");
MimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
Collection<?> mimeTypes = MimeUtil.getMimeTypes(file);
System.out.println(mimeTypes);
public String getFileContentType(String fileName) {
String fileType = "Undetermined";
final File file = new File(fileName);
try
{
fileType = Files.probeContentType(file.toPath());
}
catch (IOException ioException)
{
System.out.println(
"ERROR: Unable to determine file type for " + fileName
+ " due to exception " + ioException);
}
return fileType;
}
Я сделал это с помощью следующего кода.
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class MimeFileType {
public static void main(String args[]){
try{
URL url = new URL ("https://www.url.com.pdf");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoOutput(true);
InputStream content = (InputStream)connection.getInputStream();
connection.getHeaderField("Content-Type");
System.out.println("Content-Type "+ connection.getHeaderField("Content-Type"));
BufferedReader in = new BufferedReader (new InputStreamReader(content));
}catch (Exception e){
}
}
}