简体   繁体   English

Java:一种将 Mime(内容)类型与 CommonsMultipartFile 中的文件扩展名匹配的方法

[英]Java: A way to match Mime (content) type to file extension from CommonsMultipartFile

At my company, I need to compare the mime type to the file extension for extra reason.在我的公司,出于额外的原因,我需要将 MIME 类型与文件扩展名进行比较。 I have a CommonsMultipartFile .我有一个CommonsMultipartFile I am trying to figure out the best way to do this comparison.我试图找出进行这种比较的最佳方法。 I have seen a MimetypesFileTypeMap , but not sure if that will work here.我看过一个MimetypesFileTypeMap ,但不确定它在这里是否有效。 I am trying to avoid (or limit) any hard coding.我试图避免(或限制)任何硬编码。

I get the values as such:我得到这样的值:

CommonsMultipartFile file = ...;
String fileName = file.getOriginalFilename();
String contentType = file.getContentType();

String extension = FilenameUtils.getExtension(fileName);

I appreciate any guidance and help on this.我感谢任何有关这方面的指导和帮助。 Thanks!谢谢!

Java library for that case is quite limited (number of types).这种情况下的 Java 库非常有限(类型数量)。 This is how I do it:这就是我的做法:

static String getMimeType(String fileName) {
    // 1. first use java's built-in utils
    FileNameMap mimeTypes = URLConnection.getFileNameMap();
    String contentType = mimeTypes.getContentTypeFor(fileName);

    // 2. nothing found -> lookup our in extension map to find types like ".doc" or ".docx"
    if (contentType == null) {
        String extension = fileName.substring(fileName.lastIndexOf('.') + 1, fileName.length());;
        contentType = fileExtensionMap.get(extension);
    }
    return contentType;
}

step 2 involves having a static map:第 2 步涉及拥有静态地图:

private static final Map<String, String> fileExtensionMap;

static {
    fileExtensionMap = new HashMap<String, String>();
    // MS Office
    fileExtensionMap.put("doc", "application/msword");
    fileExtensionMap.put("dot", "application/msword");
    fileExtensionMap.put("docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
    fileExtensionMap.put("dotx", "application/vnd.openxmlformats-officedocument.wordprocessingml.template");
    fileExtensionMap.put("docm", "application/vnd.ms-word.document.macroEnabled.12");
    fileExtensionMap.put("dotm", "application/vnd.ms-word.template.macroEnabled.12");
    fileExtensionMap.put("xls", "application/vnd.ms-excel");
    fileExtensionMap.put("xlt", "application/vnd.ms-excel");
    fileExtensionMap.put("xla", "application/vnd.ms-excel");
    fileExtensionMap.put("xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    fileExtensionMap.put("xltx", "application/vnd.openxmlformats-officedocument.spreadsheetml.template");
    fileExtensionMap.put("xlsm", "application/vnd.ms-excel.sheet.macroEnabled.12");
    fileExtensionMap.put("xltm", "application/vnd.ms-excel.template.macroEnabled.12");
    fileExtensionMap.put("xlam", "application/vnd.ms-excel.addin.macroEnabled.12");
    fileExtensionMap.put("xlsb", "application/vnd.ms-excel.sheet.binary.macroEnabled.12");
    fileExtensionMap.put("ppt", "application/vnd.ms-powerpoint");
    fileExtensionMap.put("pot", "application/vnd.ms-powerpoint");
    fileExtensionMap.put("pps", "application/vnd.ms-powerpoint");
    fileExtensionMap.put("ppa", "application/vnd.ms-powerpoint");
    fileExtensionMap.put("pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation");
    fileExtensionMap.put("potx", "application/vnd.openxmlformats-officedocument.presentationml.template");
    fileExtensionMap.put("ppsx", "application/vnd.openxmlformats-officedocument.presentationml.slideshow");
    fileExtensionMap.put("ppam", "application/vnd.ms-powerpoint.addin.macroEnabled.12");
    fileExtensionMap.put("pptm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12");
    fileExtensionMap.put("potm", "application/vnd.ms-powerpoint.presentation.macroEnabled.12");
    fileExtensionMap.put("ppsm", "application/vnd.ms-powerpoint.slideshow.macroEnabled.12");
    // Open Office
    fileExtensionMap.put("odt", "application/vnd.oasis.opendocument.text");
    fileExtensionMap.put("ott", "application/vnd.oasis.opendocument.text-template");
    fileExtensionMap.put("oth", "application/vnd.oasis.opendocument.text-web");
    fileExtensionMap.put("odm", "application/vnd.oasis.opendocument.text-master");
    fileExtensionMap.put("odg", "application/vnd.oasis.opendocument.graphics");
    fileExtensionMap.put("otg", "application/vnd.oasis.opendocument.graphics-template");
    fileExtensionMap.put("odp", "application/vnd.oasis.opendocument.presentation");
    fileExtensionMap.put("otp", "application/vnd.oasis.opendocument.presentation-template");
    fileExtensionMap.put("ods", "application/vnd.oasis.opendocument.spreadsheet");
    fileExtensionMap.put("ots", "application/vnd.oasis.opendocument.spreadsheet-template");
    fileExtensionMap.put("odc", "application/vnd.oasis.opendocument.chart");
    fileExtensionMap.put("odf", "application/vnd.oasis.opendocument.formula");
    fileExtensionMap.put("odb", "application/vnd.oasis.opendocument.database");
    fileExtensionMap.put("odi", "application/vnd.oasis.opendocument.image");
    fileExtensionMap.put("oxt", "application/vnd.openofficeorg.extension");
    // Other
    fileExtensionMap.put("txt", "text/plain");
    fileExtensionMap.put("rtf", "application/rtf");
    fileExtensionMap.put("pdf", "application/pdf");
}

works fine for me, hope that helps!对我来说很好用,希望有帮助!

The most reliable method is to use Files.probeContentType , but that requires an actual file, partly because not all operating systems rely on the extension to determine the file type.最可靠的方法是使用Files.probeContentType ,但这需要实际文件,部分原因是并非所有操作系统都依赖扩展名来确定文件类型。

In Linux, the next best approach is new MimetypesFileTypeMap("/etc/mime.types") , which will be truly based on the system's mappings.在 Linux 中,下一个最好的方法是new MimetypesFileTypeMap("/etc/mime.types") ,它将真正基于系统的映射。 I don't know if OS X has a mime.types file (though a search shows that CUPS for OS X uses such a file, with an enhanced but mostly backward compatible syntax).我不知道 OS X 是否有mime.types文件(尽管搜索显示 OS X 的CUPS使用这样一个文件,具有增强但主要向后兼容的语法)。

As far as I know, there is no built-in Java class for getting MIME-type↔extension mappings in Windows.据我所知,在 Windows 中没有用于获取 MIME-type↔extension 映射的内置 Java 类。

URLConnection.getFileNameMap() returns a FileNameMap that has a decent number of entries, but still isn't based on the system's mappings. URLConnection.getFileNameMap()返回一个具有相当数量条目的 FileNameMap,但仍然不是基于系统的映射。 On my Linux system, for example, it returns null for .bz2 and .rpm files.例如,在我的 Linux 系统上,它为 .bz2 和 .rpm 文件返回 null。

FileTypeMap.getDefaultFileTypeMap() seems to have a few entries, but it too is clearly not based on the system's mappings. FileTypeMap.getDefaultFileTypeMap()似乎有几个条目,但它显然也不是基于系统的映射。 At least on my system, it returns "application/octet-stream" for .png files.至少在我的系统上,它为 .png 文件返回“application/octet-stream”。

I think the easiest thing to do is encapsulate all of them in a class:我认为最简单的方法是将它们全部封装在一个类中:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.logging.Logger;
import java.util.logging.Level;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;

public class MimeTypes {

    private static final Logger logger =
        Logger.getLogger(MimeTypes.class.getName());

    private static final String DEFAULT_TYPE = "application/octet-stream";

    private static final Path mimeTypesFile = Paths.get("/etc/mime.types");

    private final FileNameMap fileNameMap = URLConnection.getFileNameMap();

    private final FileTypeMap fileTypeMap = FileTypeMap.getDefaultFileTypeMap();

    private final FileTypeMap mimeTypesMap;

    public MimeTypes() {
        FileTypeMap map = null;
        if (Files.isRegularFile(mimeTypesFile)) {
            try {
                map = new MimetypesFileTypeMap(mimeTypesFile.toString());
            } catch (IOException e) {
                logger.log(Level.WARNING, "Couldn't read " + mimeTypesFile, e);
            }
        }
        mimeTypesMap = map;
    }

    public String getContentType(String filename) {
        String type = null;

        if (mimeTypesMap != null) {
            type = mimeTypesMap.getContentType(filename);
        }

        if (type == null || type.equals(DEFAULT_TYPE)) {
            type = fileNameMap.getContentTypeFor(filename);
        }

        if (type == null || type.equals(DEFAULT_TYPE)) {
            type = fileTypeMap.getContentType(filename);
        }

        return type;
    }

    public static void main(String[] args) {

        MimeTypes mimeTypes = new MimeTypes();

        for (String arg : args) {
            System.out.printf("Type of file \"%s\" is \"%s\"%n",
                arg, mimeTypes.getContentType(arg));
        }
    }
}

That will get you fairly good results.这会给你带来相当不错的结果。 If you want to have true platform-based MIME type checking in Windows, the only way I know to do that is to read the registry:如果您想在 Windows 中进行真正的基于平台的 MIME 类型检查,我所知道的唯一方法就是读取注册表:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.logging.Logger;
import java.util.logging.Level;
import javax.activation.FileTypeMap;
import javax.activation.MimetypesFileTypeMap;

import java.io.File;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.Collections;
import java.util.Formatter;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.ExecutionException;

public class MimeTypes {

    private static final Logger logger =
        Logger.getLogger(MimeTypes.class.getName());

    private static final String DEFAULT_TYPE = "application/octet-stream";

    private static final Path mimeTypesFile = Paths.get("/etc/mime.types");

    private final FileNameMap fileNameMap = URLConnection.getFileNameMap();

    private final FileTypeMap fileTypeMap = FileTypeMap.getDefaultFileTypeMap();

    private final FileTypeMap mimeTypesMap;

    public MimeTypes() {
        FileTypeMap map = null;

        if (Files.isRegularFile(mimeTypesFile)) {
            try {
                map = new MimetypesFileTypeMap(mimeTypesFile.toString());
            } catch (IOException e) {
                logger.log(Level.WARNING, "Couldn't read " + mimeTypesFile, e);
            }
        }

        if (map == null && System.getProperty("os.name").contains("Windows")) {
            try {
                map = new WindowsFileTypeMap();
            } catch (IOException e) {
                logger.log(Level.WARNING, "Couldn't read registered types", e);
            } catch (InterruptedException e) {
                logger.log(Level.INFO, "Interrupted; read canceled", e);
            }
        }

        mimeTypesMap = map;
    }

    public String getContentType(String filename) {
        String type = null;

        if (mimeTypesMap != null) {
            type = mimeTypesMap.getContentType(filename);
        }

        if (type == null || type.equals(DEFAULT_TYPE)) {
            type = fileNameMap.getContentTypeFor(filename);
        }

        if (type == null || type.equals(DEFAULT_TYPE)) {
            type = fileTypeMap.getContentType(filename);
        }

        return type;
    }

    private static class WindowsFileTypeMap
    extends FileTypeMap {

        private final Map<String, String> extensionToMimeType;

        public WindowsFileTypeMap()
        throws IOException,
               InterruptedException {

            ProcessBuilder builder =
                new ProcessBuilder("PowerShell.exe", "-Command", "-");

            Process process = builder.start();
            List<String> regEntryNames = getOutput(process, String.format(
                "Get-ChildItem \"Registry::HKEY_CLASSES_ROOT\\\" |"
                    + " Select-String -InputObject { $_.Name }"
                    + " -SimpleMatch -Pattern \"HKEY_CLASSES_ROOT\\.\"%n"));

            Formatter input = new Formatter();
            for (String name : regEntryNames) {
                input.format(
                    "$values = Get-ItemProperty \"Registry::%s\"%n" +
                    "$values.\"Content Type\" + \" \"%n", name);
            }

            process = builder.start();
            List<String> mimeTypes = getOutput(process, input.toString());

            int len = regEntryNames.size();
            extensionToMimeType = new HashMap<>(len);
            for (int i = 0; i < len; i++) {
                String mimeType = mimeTypes.get(i).trim();
                if (!mimeType.isEmpty()) {
                    String extension =
                        regEntryNames.get(i).replace("HKEY_CLASSES_ROOT\\", "");
                    extensionToMimeType.put(extension, mimeType);
                }
            }
        }

        @Override
        public String getContentType(File file) {
            return getContentType(file.toString());
        }

        @Override
        public String getContentType(String filename) {
            int period = filename.lastIndexOf('.');
            if (period < 0) {
                return DEFAULT_TYPE;
            }

            String ext = filename.substring(period);
            String type = extensionToMimeType.get(ext);
            return (type != null ? type : DEFAULT_TYPE);
        }

        private static List<String> getOutput(final Process process,
                                              final String input)
        throws IOException,
               InterruptedException {

            Callable<Void> inputSender = new Callable<Void>() {
                @Override
                public Void call()
                throws IOException {
                    try (BufferedWriter writer =
                        new BufferedWriter(
                            new OutputStreamWriter(
                                process.getOutputStream()))) {
                        writer.write(input);
                    }
                    return null;
                }
            };

            ExecutorService executor = Executors.newSingleThreadExecutor();
            Future<?> inputSenderStatus = executor.submit(inputSender);

            List<String> lines;
            try (BufferedReader reader =
                new BufferedReader(
                    new InputStreamReader(
                        process.getInputStream()))) {
                lines = new ArrayList<>();
                String line;
                while ((line = reader.readLine()) != null) {
                    lines.add(line);
                }
            }

            try {
                inputSenderStatus.get();
            } catch (ExecutionException e) {
                throw new IOException(e);
            }

            executor.shutdown();
            executor.awaitTermination(30, TimeUnit.SECONDS);

            process.waitFor();

            return lines;
        }
    }

    public static void main(String[] args) {

        MimeTypes mimeTypes = new MimeTypes();

        for (String arg : args) {
            System.out.printf("Type of file \"%s\" is \"%s\"%n",
                arg, mimeTypes.getContentType(arg));
        }
    }
}

I have a class https://github.com/nablex/utils-io/blob/master/src/main/java/be/nabu/utils/io/ContentTypeMap.java that does this.我有一个类https://github.com/nablex/utils-io/blob/master/src/main/java/be/nabu/utils/io/ContentTypeMap.java这样做。

It adds a few things that are missing in the URLConnection stuff:它添加了 URLConnection 内容中缺少的一些内容:

  • it can handle 1-* relationships in both directions (one mime type, multiple extensions and the other way around)它可以在两个方向上处理 1-* 关系(一种 mime 类型,多个扩展名,反之亦然)
  • you can go both directions (mimetype > extension and extension > mimetype)你可以去两个方向(mimetype > 扩展和扩展 > mimetype)

Additionally it can be plugged into the URLConnection using:此外,它可以插入到 URLConnection 使用:

ContentTypeMap.register()

By default it uses a file to load the mappings: https://github.com/nablex/utils-io/blob/master/src/main/resources/mime.properties默认情况下,它使用一个文件来加载映射: https : //github.com/nablex/utils-io/blob/master/src/main/resources/mime.properties

boolean getMimeType(String fileName) {
boolean flag=false;
Map<String, String> fileExtnMap= new HashMap<String, String>();
fileExtnMap.put("jpg","image/jpg");
fileExtnMap.put("jpeg","image/jpeg");
fileExtnMap.put("pdf","application/pdf");

FileNameMap fileMap = URLConnection.getFileNameMap();
String contentType=fileMap .getContentTypeFor(fileName);
String[] extn= fileName.split("\\.");
contentType = fileExtnMap.get(extn[1]);
if(extn[1].equals("pdf") && contentType.equals("application/pdf") || extn[1].equals("jpg") && contentType.equals("image/jpg") || extn[1].equals("jpeg") && contentType.equals("image/jpeg")){
    flag=true;
}
    
    return flag;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM