Ответ 1
В Java 7 теперь вы можете просто использовать Files.probeContentType(path)
.
Мне просто интересно, как большинство людей выбирает тип mime из файла на Java? До сих пор я пробовал два utils: JMimeMagic
и Mime-Util
.
Первые дали мне исключения для памяти, вторая не закрывает свои потоки должным образом. Мне просто интересно, есть ли у кого-нибудь другой метод/библиотека, которые они использовали и работали правильно?
В 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 (это отличная библиотека, использующая как расширение файла, так и контент).
API JAF является частью JDK 6. Посмотрите <. →
Наиболее интересными классами являются 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 вам нужно всего три строчки кода:
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 для получения дополнительной информации.
Apache Tika предлагает в tika-core mime типа, основанного на волшебных маркерах в префиксе потока. 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);
}
От roseindia:
FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mimeType = fileNameMap.getContentTypeFor("alert.gif");
Если вы застряли с Java 5-6, то этот служебный класс из серво продукта с открытым исходным кодом.
Вам нужна только эта функция
public static String getContentType(byte[] data, String name)
Он проверяет первые байты содержимого и возвращает типы содержимого на основе этого содержимого, а не по расширению файла.
Мне было просто интересно, как большинство людей выбирают 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();
}
Чтобы скинуть мои 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). Однако очень просто добавить любой тип контента, который вам может понадобиться:
Пример записи для файлов 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, вы должны найти библиотеку с большинством звездочек рядом с ее именем и использовать ее. Для этого конкретного случая мне не нужен один (пока;)).
Я попробовал несколько способов сделать это, в том числе первые, которые сказал @Joshua Fox. Но некоторые из них не распознают частые миметики, например, для файлов 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();
Лучше использовать проверку двух уровней для загрузки файлов.
Сначала вы можете проверить mimeType и проверить его.
Во-вторых, вы должны преобразовать первые 4 байта вашего файла в шестнадцатеричный, а затем сравнить его с магическими числами. Тогда это будет действительно безопасный способ проверить проверки файлов.
в файле spring MultipartFile;
org.springframework.web.multipart.MultipartFile
file.getContentType();
Это самый простой способ, который я нашел для этого:
byte[] byteArray = ...
InputStream is = new BufferedInputStream(new ByteArrayInputStream(byteArray));
String mimeType = URLConnection.guessContentTypeFromStream(is);
если вы работаете с операционной системой 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'
Попробовав различные библиотеки, я установил 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;
}
Вы можете сделать это всего одной строкой: 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
File file = new File(PropertiesReader.FILE_PATH);
MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
String mimeType = fileTypeMap.getContentType(file);
URLConnection uconnection = file.toURL().openConnection();
mimeType = uconnection.getContentType();