文件识别浅谈(含office文件区分)
前言
本文主要根据后台接口识别Office文件类型这一话题做一些分享,主要方向还是放在不能获取到文件名情况下的Office文件识别。
可获取到文件名
如果后端接口可以获取到完成的文件名称,则整个过程会变得很轻松,如果不考虑到客户恶意修改后缀名的情况,我们只需要对获取到的文件名进行截取即可,整个截取的代码种类也很多,下面分享一个我的实现。
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文件识别还存在一定的匹配错误。
根据微软文档给出的信息可以知道MS Office是以二进制进行存储的,需要根据其文档给出的读取方式进行读取,这样应该是可以判断各个文件类型的,笔者没有对这个文档做深入研究,这里主要讲一下我对新版本office的处理方式(xlxs、pptx、docx)的处理方式,细心的读者可能已经发现docx和zip的16进制文件头是基本一致,我们将docx文件使用压缩文件打开,可以发现其中包含一个文件:[Content_Types].xml:
<?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。
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;
}
文件识别浅谈(含office文件区分)的更多相关文章
- oracle: 浅谈sqlnet.ora文件的作用,及SQLNET.AUTHENTICATION_SERVICES设置
关于sqlnet.ora的说明: *****************************************************FROM ORACLE11G DOCS*********** ...
- JAVA NIO之浅谈内存映射文件原理与DirectMemory
JAVA类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...
- 浅谈python中文件和文件夹的相关操作
文件操作 文件的打开与关闭 打开文件 使用open(文件名,访问方式)函数,可以打开一个已存在的文件,或者创建一个新的文件. 示例如下: f = open('test.txt') # 访问方式可以省略 ...
- 【NIO】NIO之浅谈内存映射文件原理与DirectMemory
Java类库中的NIO包相对于IO 包来说有一个新功能是内存映射文件,日常编程中并不是经常用到,但是在处理大文件时是比较理想的提高效率的手段.本文我主要想结合操作系统中(OS)相关方面的知识介绍一下原 ...
- 浅谈MySQL日志文件|手撕MySQL|对线面试官
关注微信公众号[程序员白泽],进入白泽的知识分享星球 前言 上周五面试了字节的第三面,深感数据库知识的重要,我也意识到在平时的学习中,自己对于数据库的学习较为薄弱.甚至在有过一定实习经验之后,依旧因为 ...
- c#Winform程序调用app.config文件配置数据库连接字符串 SQL Server文章目录 浅谈SQL Server中统计对于查询的影响 有关索引的DMV SQL Server中的执行引擎入门 【译】表变量和临时表的比较 对于表列数据类型选择的一点思考 SQL Server复制入门(一)----复制简介 操作系统中的进程与线程
c#Winform程序调用app.config文件配置数据库连接字符串 你新建winform项目的时候,会有一个app.config的配置文件,写在里面的<connectionStrings n ...
- 浅谈 举家搬迁静态文件到CDN
由于七牛CDN最近做活动,对于标准用户可以免费使用如下优惠 10 GB 存储空间 10 G/月 下载流量 10 万次/月 PUT/DELETE 请求 100 万次/月 GET 请求 以上这些指标直接就 ...
- 浅谈qmake之pro、pri、prf、prl文件
浅谈qmake之pro.pri.prf.prl文件 转载自:http://blog.csdn.net/dbzhang800/article/details/6348432 尽管每次和cmake对比起来 ...
- 浅谈JS中的!=、== 、!==、===的用法和区别 JS中Null与Undefined的区别 读取XML文件 获取路径的方式 C#中Cookie,Session,Application的用法与区别? c#反射 抽象工厂
浅谈JS中的!=.== .!==.===的用法和区别 var num = 1; var str = '1'; var test = 1; test == num //tr ...
随机推荐
- sqlplus登录信息,列出所有表,列在表结构,sqlplus行和列显示设置,别名,Null值问题,细木工,DISTINCT
1 sqlplus登录方式: 普通用户登录: 登录eg:C:\>sqlplusscott/11 (格式:sqlplus username/password) 退出eg:quit退出 超级 ...
- Erlang实现进程池
开发工作中,经常会碰到进程池或者线程池,或者其它的资源池.在这里,用erlang实现一个简单的进程池. erlang进程是非常轻量级的,这个进程池的主要目的是用一种通用的方式去管理和限制系统中运行的资 ...
- ssm框架插入mysql数据库中文乱码问题解决
1. 检查web.xml <!-- 编码过滤器 --> <filter> <filter-name>encodingFilter</filter-n ...
- WinForm导出文件
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 ...
- rocksdb源码——性能诊断
该文前三部份介绍 statistics.perf context和iostat context和thread status相关内容.最后介绍ThreadLocalPtr实现的原理. 0. 性能诊断类型 ...
- 从源码角度看MySQL memcached plugin——1. 系统结构和引擎初始化
本章尝试回答两个问题: 一.memcached plugin与MySQL的关系: 二.MySQL系统如何启动memcached plugin. 1. memcached plugin与MySQL的关系 ...
- cocos2d-x 源代码分析 : Ref (CCObject) 源代码分析 cocos2d-x内存管理策略
从源代码版本号3.x.转载请注明 cocos2d-x 总的文件夹的源代码分析: http://blog.csdn.net/u011225840/article/details/31743129 1.R ...
- 关闭Mac OS 的Rootless
今天在使用mac的时候,需要删除 /usr/bin/下的 自带的php文件.然后提示Operation not permitted 使用sudo 依然不可以,通过google 得到解决方案. 需要关闭 ...
- express的路由规则
路由规则 express 封装了多种 http 请求方式,我们主要只使用 get 和 post 两种. get 和 post 的第一个参数都为请求的路径,第二个参数为处理请求的回调函数,回调函数有两个 ...
- 【C/S通信交互之Http篇】Cocos2dx(Client)使用Curl与Jetty(Server)实现手机网游Http通信框架(内含解决curl.h头文件找不到问题)
之前已经分享过一篇基于Cocos2dx与服务器使用Socket进行通信的框架,还不太熟悉的请移步到如下博文中: [C/S通信交互之Socket篇]Cocos2dx(Client)使用BSD Socke ...