Pergunta

Eu estava me perguntando como a maioria das pessoas busca um tipo MIME de um arquivo em Java.Até agora eu tentei dois utilitários: JMimeMagic & Mime-Util.

O primeiro me deu exceções de memória, o segundo não fecha seus fluxos corretamente.Eu só queria saber se alguém mais tinha um método/biblioteca que usou e funcionou corretamente?

Foi útil?

Solução

No Java 7 agora você pode apenas usar Files.probeContentType(path).

Outras dicas

Infelizmente,

mimeType = file.toURL().openConnection().getContentType();

não funciona, pois esse uso de URL deixa um arquivo bloqueado, de modo que, por exemplo, não pode ser excluído.

No entanto, você tem isto:

mimeType= URLConnection.guessContentTypeFromName(file.getName());

e também o seguinte, que tem a vantagem de ir além do mero uso da extensão do arquivo, e dá uma espiada no conteúdo

InputStream is = new BufferedInputStream(new FileInputStream(file));
mimeType = URLConnection.guessContentTypeFromStream(is);
 //...close stream

No entanto, como sugerido pelo comentário acima, a tabela interna de tipos MIME é bastante limitada, não incluindo, por exemplo, MSWord e PDF.Então, se você quiser generalizar, você precisará ir além das bibliotecas internas, usando, por exemplo, Mime-Util (que é uma ótima biblioteca, usando extensão de arquivo e conteúdo).

A API JAF faz parte do JDK 6.Olhe para javax.activation pacote.

As aulas mais interessantes são javax.activation.MimeType - um suporte real do tipo MIME - e javax.activation.MimetypesFileTypeMap - classe cuja instância pode resolver o tipo MIME como String para um arquivo:

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);

Com Apache Tika você precisa apenas três linhas de código:

File file = new File("/path/to/file");
Tika tika = new Tika();
System.out.println(tika.detect(file));

Se você tiver um console bacana, basta colar e executar este código para brincar com ele:

@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)

Lembre-se de que suas APIs são ricas e podem analisar “qualquer coisa”.A partir do tika-core 1.14, você tem:

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)

Ver os apidocs Para maiores informações.

Apache Tika ofertas em tika-core uma detecção de tipo MIME baseada em marcadores mágicos no prefixo do fluxo. tika-core não busca outras dependências, o que o torna tão leve quanto o atualmente não mantido Utilitário de detecção de tipo Mime.

Exemplo de código simples (Java 7), usando as variáveis theInputStream e 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();
}

Observe que MediaType.detect(...) não pode ser usado diretamente (TIKA-1120).Mais dicas são fornecidas em https://tika.apache.org/0.10/detection.html.

Se você é um desenvolvedor Android, pode usar uma classe de utilitário android.webkit.MimeTypeMap que mapeia tipos MIME para extensões de arquivo e vice-versa.

O trecho de código a seguir pode ajudá-lo.

private static String getMimeType(String fileUrl) {
    String extension = MimeTypeMap.getFileExtensionFromUrl(fileUrl);
    return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}

De rosaíndia:

FileNameMap fileNameMap = URLConnection.getFileNameMap();
String mimeType = fileNameMap.getContentTypeFor("alert.gif");

Se você está preso com java 5-6 então esta classe utilitária de produto de código aberto servoy.

Você só precisa desta função

public static String getContentType(byte[] data, String name)

Ele investiga os primeiros bytes do conteúdo e retorna os tipos de conteúdo com base nesse conteúdo e não por extensão de arquivo.

Eu estava me perguntando como a maioria das pessoas busca um tipo MIME de um arquivo em Java.

Eu publiquei meu SimpleMagic Pacote Java que permite a determinação do tipo de conteúdo (tipo MIME) a ​​partir de arquivos e matrizes de bytes.Ele foi projetado para ler e executar os arquivos mágicos do comando Unix file(1) que fazem parte da maioria das configurações do sistema operacional ~Unix.

Eu tentei o Apache Tika, mas é enorme com toneladas de dependências, URLConnection não usa os bytes dos arquivos, e MimetypesFileTypeMap também apenas olha os nomes dos arquivos.

Com SimpleMagic você pode fazer algo como:

// 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();
}

Para contribuir com meus 5 centavos:

TL, DR

eu uso MimetypesFileTypeMap e adicione qualquer mime que não esteja lá e eu precise dele especificamente, no arquivo mime.types.

E agora, a longa leitura:

Primeiro de tudo, a lista de tipos MIME é enorme, Veja aqui: https://www.iana.org/assignments/media-types/media-types.xhtml

Gosto de usar primeiro os recursos padrão fornecidos pelo JDK e, se isso não funcionar, irei procurar outra coisa.

Determine o tipo de arquivo pela extensão do arquivo

Desde a versão 1.6, Java possui MimetypesFileTypeMap, conforme apontado em uma das respostas acima, e é a maneira mais simples de determinar o tipo MIME:

new MimetypesFileTypeMap().getContentType( fileName );

Na sua implementação vanilla, isso não faz muito (ou seja,funciona para .html, mas não para .png).No entanto, é muito simples adicionar qualquer tipo de conteúdo necessário:

  1. Crie um arquivo chamado 'mime.types' na pasta META-INF do seu projeto
  2. Adicione uma linha para cada tipo MIME que você precisa e a implementação padrão não fornece (existem centenas de tipos MIME e a lista aumenta com o passar do tempo).

Entradas de exemplo para arquivos png e js seriam:

image/png png PNG
application/javascript js

Para o formato de arquivo mime.types, veja mais detalhes aqui: https://docs.oracle.com/javase/7/docs/api/javax/activation/MimetypesFileTypeMap.html

Determinar o tipo de arquivo a partir do conteúdo do arquivo

Desde 1.7, Java tem java.nio.file.spi.FileTypeDetector, que define uma API padrão para determinar um tipo de arquivo em maneira específica de implementação.

Para buscar o tipo MIME para um arquivo, você simplesmente usaria arquivos e faça isso no seu código:

Files.probeContentType(Paths.get("either file name or full path goes here"));

A definição da API fornece recursos que suportam a determinação do tipo MIME do arquivo a partir do nome do arquivo ou do conteúdo do arquivo (bytes mágicos).Por isso probeContentType() O método lança IOException, caso uma implementação desta API use o Path fornecido para realmente tentar abrir o arquivo associado a ela.

Novamente, baunilha implementação disso (aquele que vem com o JDK) deixa muito a desejar.

Em algum mundo ideal em uma galáxia muito, muito distante, todas essas bibliotecas que tentam resolver esse problema de arquivo para tipo MIME simplesmente implementariam java.nio.file.spi.FileTypeDetector, você colocaria o arquivo jar da biblioteca de implementação preferencial em seu caminho de classe e pronto.

No mundo real, onde você precisa da seção TL,DR, você deve encontrar a biblioteca com mais estrelas ao lado do nome e usá-la.Para este caso específico, não preciso de um (ainda;)).

Tentei várias maneiras de fazer isso, inclusive as primeiras ditas por @Joshua Fox.Mas alguns não reconhecem tipos MIME frequentes, como arquivos PDF, e outros não podem ser confiáveis ​​com arquivos falsos (tentei com um arquivo RAR com extensão alterada para TIF).A solução que encontrei, como também é dito por @Joshua Fox de forma superficial, é usar MimeUtil2, assim:

MimeUtil2 mimeUtil = new MimeUtil2();
mimeUtil.registerMimeDetector("eu.medsea.mimeutil.detector.MagicMimeMimeDetector");
String mimeType = MimeUtil2.getMostSpecificMimeType(mimeUtil.getMimeTypes(file)).toString();

É melhor usar validação de duas camadas para upload de arquivos.

Primeiro você pode verificar o mimeType e validá-lo.

Em segundo lugar, você deve converter os primeiros 4 bytes do seu arquivo para hexadecimal e depois compará-lo com os números mágicos.Então será uma maneira realmente segura de verificar validações de arquivos.

na primavera MultipartFile arquivo;

org.springframework.web.multipart.MultipartFile

file.getContentType();

Esta é a maneira mais simples que encontrei para fazer isso:

byte[] byteArray = ...
InputStream is = new BufferedInputStream(new ByteArrayInputStream(byteArray));
String mimeType = URLConnection.guessContentTypeFromStream(is);

se você trabalha no sistema operacional Linux, há uma linha de comando 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 "";
}

Então

mimetype("/home/nyapp.war") //  'application/zip'

mimetype("/var/www/ggg/au.mp3") //  'audio/mp3'

Depois de tentar várias outras bibliotecas, optei pelo 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;
}

Você pode fazer isso com apenas uma linha: MimetypesFileTypeMap().getContentType(novo arquivo("nome do arquivo.ext")).Veja o código de teste completo (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")));
    }
}

Este código produz a seguinte saída: texto/simples

File file = new File(PropertiesReader.FILE_PATH);
MimetypesFileTypeMap fileTypeMap = new MimetypesFileTypeMap();
String mimeType = fileTypeMap.getContentType(file);
URLConnection uconnection = file.toURL().openConnection();
mimeType = uconnection.getContentType();
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top