本文主要根据后台接口识别Office文件类型这一话题作一些分享,主要方向仍是放在不能获取到文件名状况下的Office文件识别。java
若是后端接口能够获取到完成的文件名称,则整个过程会变得很轻松,若是不考虑到客户恶意修改后缀名的状况,咱们只须要对获取到的文件名进行截取便可,整个截取的代码种类也不少,下面分享一个个人实现。web
public static String parseFileType(String originName) { if (StringUtils.isBlank(originName)) { return null; } else { int i = originName.lastIndexOf("\\"); int j = originName.lastIndexOf("/"); int index = i > j ? i : j; if (index == originName.length() - 1) { return null; } else { String name = originName.substring(index + 1); if (!name.contains(".")) { return null; } else { if (name.lastIndexOf("." ) + 1 == name.length()) { return null; } else { return name.substring(name.lastIndexOf(".") + 1, name.length()).toLowerCase(); } } } } }
咱们根据经常使用文件类型拥有必定固定的文件头这种方式能够实现对接口中的文件流作必定程度上的文件识别,这里分享一个简单的实现方式。后端
public static String getFileTypeByStream(byte[] b) { Map FILE_TYPE_MAP = new HashMap(); FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000","doc"); //MS Excel 注意:word、msi 和 excel的文件头同样 FILE_TYPE_MAP.put("504b0304", "docx");//docx,xlxs,pptx文件 FILE_TYPE_MAP.put("d0cf11e0a1b11ae10000", "wps");//WPS文字wps、表格et、演示dps都是同样的 FILE_TYPE_MAP.put("255044462D312E", "pdf"); //Adobe Acrobat (pdf) StringBuilder stringBuilder = new StringBuilder(); if (b == null || b.length <= 0) { return null; } for (byte element : b) { int v = element & 0xFF; String hv = Integer.toHexString(v); if (hv.length() < 2) { stringBuilder.append(0); } stringBuilder.append(hv); } String filetypeHex = String.valueOf(stringBuilder.toString()).substring(0, 20); System.out.println(filetypeHex); Iterator<Entry<String, String>> entryiterator = FILE_TYPE_MAP.entrySet().iterator(); while (entryiterator.hasNext()) { Entry<String, String> entry = entryiterator.next(); String fileTypeHexKey = entry.getKey().toUpperCase(); if (filetypeHex.toUpperCase().startsWith(fileTypeHexKey)) { return entry.getValue(); } } return null; }
这种方式对一些图片视频文件类型识别较为准确,可是对于office文件的识别表现的不是太尽如人意,他没法区分excel,ppt,word等三种文件,且有些形式的office文件识别还存在必定的匹配错误。app
根据微软文档给出的信息能够知道MS Office是以二进制进行存储的,须要根据其文档给出的读取方式进行读取,这样应该是能够判断各个文件类型的,笔者没有对这个文档作深刻研究,这里主要讲一下我对新版本office的处理方式(xlxs、pptx、docx)的处理方式,细心的读者可能已经发现docx和zip的16进制文件头是基本一致,咱们将docx文件使用压缩文件打开,能够发现其中包含一个文件:[Content_Types].xml:dom
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"> <Default Extension="png" ContentType="image/png"/> <Default Extension="bin" ContentType="application/vnd.openxmlformats-officedocument.oleObject"/> <Default Extension="jpeg" ContentType="image/jpeg"/><Default Extension="emf" ContentType="image/x-emf"/> <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/> <Default Extension="xml" ContentType="application/xml"/> <Default Extension="jpg" ContentType="image/jpeg"/> <Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/> <Override PartName="/customXml/itemProps1.xml" ContentType="application/vnd.openxmlformats-officedocument.customXmlProperties+xml"/> <Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml"/> <Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml"/> <Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml"/> <Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml"/> <Override PartName="/word/footnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml"/> <Override PartName="/word/endnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml"/> <Override PartName="/word/header1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/> <Override PartName="/word/header2.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/> <Override PartName="/word/footer1.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/> <Override PartName="/word/footer2.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/> <Override PartName="/word/header3.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/> <Override PartName="/word/footer3.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/> <Override PartName="/word/header4.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml"/> <Override PartName="/word/footer4.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml"/> <Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml"/> <Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/> <Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/> <Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/> </Types>
其基本包含了整个文件中包含的内容,咱们对其中一个key-value进行识别便可,docx的标志性PartName为"/word/document.xml“,xlsx的标志性PartName为/xl/workbook.xml。ide
private static List<String> parseFilePartNameList(MultipartFile file) throws IOException, JDOMException{ List<String> partNames=new ArrayList<>(); ZipInputStream zipStream = new ZipInputStream(file.getInputStream()); BufferedInputStream bufferStream = new BufferedInputStream(zipStream); ZipEntry entry; while ((entry = zipStream.getNextEntry()) != null) { String fileName = entry.getName(); if (fileName.equals("[Content_Types].xml")) { SAXBuilder builder = new SAXBuilder(); byte[] xmlbytes = new byte[(int) entry.getSize()]; bufferStream.read(xmlbytes, 0, (int) entry.getSize()); InputStream byteArrayInputStream = new ByteArrayInputStream(xmlbytes); org.jdom.Document document = builder.build(byteArrayInputStream); org.jdom.Element foo = document.getRootElement(); List<Element> chilLst = foo.getChildren(); for (Element child : chilLst) { String partNameValue = child.getAttributeValue("PartName"); if (StringUtils.isBlank(partNameValue)) { partNames.add(partNameValue); } } } } return partNames; }