纯js判断文件流格式类型:pdf,doc,docx,xls,xlsx,ppt,pptx一次搞定!

Posted csdnyiiran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了纯js判断文件流格式类型:pdf,doc,docx,xls,xlsx,ppt,pptx一次搞定!相关的知识,希望对你有一定的参考价值。

目录

使用js判断文件类型的场景

在开发纯前端基于react框架的文件预览组件时,需要根据不同的文件类型,分发给不同的组件去完成预览。网上已有的开源项目通常是通过传递文件名参数,通过后缀名字符串匹配区分文件类型。
但是这种做法需要用户传递准确文件名称与后缀名,如果你的文件是从服务端获取的,也同样要求后端开发准确拥有这些信息。可是,如果能直接从文件流中判断出文件类型的话,文件名参数完全可以省略,就能实现预览效果,对用户或是服务端的依赖就大大降低了。
这个文件预览项目本文实现的功能函数github地址,都放在文件末尾了。目前实现了react框架pdf,xls,xlsx,docx这几种格式的预览,其中pdf预览实现了toolbar的基础操作功能。欢迎批评交流,如果有帮到你,请帮我点亮star吧。

方法特点

网络上很多方法仅仅通过文件流的头部编码,只能区分文件属于Microsoft2003规范(doc,xls,ppt)或Microsoft2007规范(docx,xlsx,pptx),但是对同一版本内部的具体类型是无法区分的。因为Microsoft2007规范的docx,xlsx,pptx等格式,本质上都是zip类型的文件,文件流开头的几位16进制数都是统一的“0x50,0x4b,0x03,0x04,…”。本方法在区分这两类规范的基础上进行了扩展,能有效识别各个规范下的具体文件类型。

输入输出

输入:文件的arrayBuffer数据
输出:‘file2003,file2007,pdf,doc,docx,xls,xlsx,ppt,pptx,other’之一。

方法步骤

1. 查看每种格式文件的16进制码,提取不同文件类型的“特征数”。

这一步用vscode就能完成。首先可以安装一款Hex Editor插件,用来展示16进制文件流。

把文件放到vscode中打开,左边是文档的16进制码(0x25,0x50…),右边是将16进制数转换成的ascii码(通过String.fromCharCode就可以转换)。这种模式可以直观地看到每个文件的关键词信息。

pdf文件的开头几个数字是唯一的,因此只要拿到文件流,很好判断一定是pdf文件。

docx,xlsx,pptx文件的文件头标识信息是一样的,通过这几位固定数字能判断出来是Microsoft2007新标准的文件。

但是这些文件的结尾位置也出现了关键词,而且是每种类型唯一的,因此不仅可以获取文件头,也可以专门获取文件尾部的一段数据来判断。
下图是docx文件

下图是xlsx文件,关键词是/worksheets
同理,pptx文件的关键词是ppt/,也出现在文件结尾位置。
Microsoft2003规范的文件开头,都是统一的’d0’, ‘cf’, ‘11’, ‘e0’。
xls的关键词是Microsoft Excel。
doc的关键词是Microsoft Word。
ppt的关键词是PowerPoint Document。

下面的工作就是,获取文件流的不同位置的数据,放在一个数组中,来判断这个数组是否包含以上含有特征的16进制数。

2. 先判断大类型,在具体大类下判断小类型

1)需要整理一下刚刚总结的各个格式与特征数的对应关系,整理成json格式。

//大类
const formatMap = 
    'pdf': ['25', '50', '44', '46'],`在这里插入代码片`
    'file2003': ['d0', 'cf', '11', 'e0'],
    'file2007': ['50', '4b', '03', '04', '14', '00', '06', '00'],

//区分xlsx,pptx,docx三种格式的特征数。通过每个文件末尾的关键词检索判断
const format2007Map = 
    xlsx: ['77', '6f', '72', '6b', '73', '68', '65', '65', '74', '73', '2f'],// 转换成ascii码的含义是 worksheets/
    docx: ['77', '6f', '72', '64', '2f'],// 转换成ascii码的含义是 word/
    pptx: ['70', '70', '74', '2f'],// 转换成ascii码的含义是 ppt/

//区分xls,ppt,doc三种格式的特征数,关键词同样出现在文件末尾
const pptFormatList = ['50', '6f', '77', '65', '72', '50', '6f', '69', '6e', '74', '20', '44', '6f', '63', '75', '6d', '65', '6e', '74'];// 转换成ascii码的含义是 PowerPoint Document
const format2003Map = 
    xls: ['4d', '69', '63', '72', '6f', '73', '6f', '66', '74', '20', '45', '78', '63', '65', '6c'],// 转换成ascii码的含义是 Microsoft Excel
    doc: ['4d', '69', '63', '72', '6f', '73', '6f', '66', '74', '20', '57', '6f', '72', '64'],// 转换成ascii码的含义是 Microsoft Word
    ppt: pptFormatList.join(',00,').split(',')

//xls格式的文件还有一种例外情况,就是保存为.html格式的文件。特征码是office:excel
let xlsHtmlTarget = ['6f', '66', '66', '69', '63', '65', '3a', '65', '78', '63', '65', '6c']; 

2)把arraybuffer数据先使用Unit8Array转换成数组,再转化成16进制(为便于比较,省略了’0x’,只保留后两位)。同时,我们每次运算不需要使用全部的数组数据,而是找到对应位置的一部分,所以通过slice方法来截取我们期望位置的数组。

这里要说明,具体应该截取文件的什么位置,是打开若干个文件之后估计的大概范围,这个范围越大,匹配的成功率越高,但是要在数组遍历的效率之间做一个平衡。不排除有一些文件因为标准兼容的问题,关键词出现的位置跟我们截取的位置不一样,导致最后判断错误的可能性。

 //截取部分数组,并转化成16进制
function getSliceArrTo16(arr, start, end) 
    let newArr = arr.slice(start, end);
    return Array.prototype.map
        .call(newArr, (x) => ('00' + x.toString(16)).slice(-2));

//判断arr数组是否包含target数组,且不能乱序。如果数组比较小,直接将两个数组转换成字符串比较。
//在数组长度大于500的情况下,写了如下方法来提高检索的效率:
function isListContainsTarget(target, arr) 
    let i = 0;
    while (i < arr.length) 
        if (arr[i] == target[0]) 
            let temp = arr.slice(i, i + target.length);
            if (temp.join() === target.join()) 
                return true
            
        
        i++;
    

具体的判断方法:

export default function getFileTypeFromArrayBuffer(arrayBuffer) 
	try 
        if (Object.prototype.toString.call(arrayBuffer) !== '[object ArrayBuffer]') 
            throw new TypeError("The provided value is not a valid ArrayBuffer type.")
        
        let arr = new Uint8Array(arrayBuffer);
		let str_8 = getSliceArrTo16(arr, 0, 8).join('');  //只截取了前8位
		//为了简便,匹配的位置索引我选择在代码里直接固定写出,你也可以把相应的索引配置在json数据里。
		//第一次匹配,只匹配数组前八位,得到大范围的模糊类型
		let result = '';
		for (let type in formatMap) 
		    let target = formatMap[type].join('');
		    if (~str_8.indexOf(target))  //相当于(str_8.indexOf(target) !== '-1')
		        result = type;
		        break;
		    
		
		
		if (!result) 
			//第一次匹配失败,不属于file2003,file2007,pdf。有可能是html格式的xls文件
			//通过前50-150位置判断是否是xls
		    let arr_start_16 = getSliceArrTo16(arr, 50, 150);
		    if (~(arr_start_16.join('').indexOf(xlsHtmlTarget.join('')))) 
		        return 'xls';
		    
		    return 'other';
		
		if (result == 'pdf') 
		     return result;
		 
		 if (result == 'file2007') 
		     //默认是xlsx,pptx,docx三种格式中的一种,进行第二次匹配.如果未匹配到,结果仍然是file2007
		     let arr_500_16 = getSliceArrTo16(arr, -500);
		     for (let type in format2007Map) 
		         let target = format2007Map[type];
		         if (isListContainsTarget(target, arr_500_16)) 
		             result = type;
		             break;
		         
		     
		     return result;
		 
		 if (result == 'file2003') 
		     let arr_end_16 = getSliceArrTo16(arr, -550, -440);
		     for (let type in format2003Map) 
		         let target = format2003Map[type];
		         //通过倒数440-550位置判断是否是doc/ppt/xls
		         if (~(arr_end_16.join('').indexOf(target.join('')))) 
		             result = type;
		             break
		         
		     
		     return result;
		 
		//未匹配成功
		return 'other';

    
        

项目地址:

纯前端基于react实现的多类型文件预览:

https://github.com/react-office-viewer/react-office-viewer.git

通过arraybuffer判断文件类型:

https://github.com/react-office-viewer/getFileTypeFromArrayBuffer.git

结语

最后,本文最希望的就是为大家提供一种区分文件格式的思路,在实际操作中可以用更加丰富细致的标准来不断提升判断的准确率。欢迎大家留言交流。

用java读取多种文件格式的文件(pdf,pptx,ppt,doc,docx..)

   本文通过开源pdfbox和poi进行处理多种文件格式的文本读入

 1.需要的jar的maven坐标:

     <dependency>
            <groupId>org.apache.pdfbox</groupId>
            <artifactId>pdfbox</artifactId>
            <version>2.0.2</version>
        </dependency>
        <!--  ppt,xls,docx,pptx,xlsx-->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml-schemas</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-scratchpad</artifactId>
            <version>3.14</version>
        </dependency>
        <dependency>
            <groupId>org.apache.xmlbeans</groupId>
            <artifactId>xmlbeans</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
    

 

 处理多种文件格式,详情见代码:

  1 package cn.lcg.utils;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.IOException;
  6 import java.text.NumberFormat;
  7 import java.util.List;
  8 
  9 import org.apache.pdfbox.pdmodel.PDDocument;
 10 import org.apache.pdfbox.text.PDFTextStripper;
 11 import org.apache.poi.hslf.extractor.PowerPointExtractor;
 12 import org.apache.poi.hssf.usermodel.HSSFCell;
 13 import org.apache.poi.hssf.usermodel.HSSFRow;
 14 import org.apache.poi.hssf.usermodel.HSSFSheet;
 15 import org.apache.poi.hssf.usermodel.HSSFWorkbook;
 16 import org.apache.poi.hwpf.HWPFDocument;
 17 import org.apache.poi.hwpf.usermodel.Range;
 18 import org.apache.poi.ss.usermodel.Cell;
 19 import org.apache.poi.xslf.usermodel.XMLSlideShow;
 20 import org.apache.poi.xslf.usermodel.XSLFSlide;
 21 import org.apache.poi.xslf.usermodel.XSLFSlideShow;
 22 import org.apache.poi.xssf.usermodel.XSSFCell;
 23 import org.apache.poi.xssf.usermodel.XSSFRow;
 24 import org.apache.poi.xssf.usermodel.XSSFSheet;
 25 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 26 import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
 27 import org.apache.poi.xwpf.usermodel.XWPFDocument;
 28 import org.openxmlformats.schemas.drawingml.x2006.main.CTRegularTextRun;
 29 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;
 30 import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraph;
 31 import org.openxmlformats.schemas.presentationml.x2006.main.CTGroupShape;
 32 import org.openxmlformats.schemas.presentationml.x2006.main.CTShape;
 33 import org.openxmlformats.schemas.presentationml.x2006.main.CTSlide;
 34 
 35 /**
 36  * 
 37  * @author yujian
 38  * @date   2016年10月12日
 39  * @version 0.0.1
 40  */
 41 public class FileFormat {
 42     /**
 43      * 用来读取doc文件的方法
 44      * @param filePath
 45      * @return
 46      * @throws Exception
 47      */
 48     public static String getTextFromDoc(String filePath) throws Exception{
 49         StringBuilder sb = new StringBuilder();
 50             FileInputStream fis = new FileInputStream(new File(filePath));
 51             HWPFDocument doc = new HWPFDocument(fis);
 52             Range rang = doc.getRange();
 53             sb.append(rang.text());    
 54             fis.close();
 55             return sb.toString();
 56         
 57     }
 58     /**
 59      * 用来读取docx文件
 60      * @param filePath
 61      * @return
 62      * @throws IOException 
 63      * @throws Exception
 64      */
 65     @SuppressWarnings("resource")
 66     public static String getTextFromDocx(String filePath) throws IOException {
 67         FileInputStream in = new FileInputStream(filePath);
 68         XWPFDocument doc = new XWPFDocument(in);
 69         XWPFWordExtractor extractor = new XWPFWordExtractor(doc);
 70         String text = extractor.getText();
 71         in.close();
 72         return text;
 73     }
 74     /**
 75      * 用来读取pdf文件
 76      * @param filePath
 77      * @return
 78      * @throws IOException
 79      */
 80     public static String getTextFromPDF(String filePath) throws IOException{
 81             File input = new File(filePath);
 82             PDDocument pd = PDDocument.load(input);
 83             PDFTextStripper stripper = new PDFTextStripper();
 84             return stripper.getText(pd);
 85     }
 86     /**
 87      * 用来读取ppt文件
 88      * @param filePath
 89      * @return
 90      * @throws IOException
 91      */
 92     public static String getTextFromPPT( String filePath) throws IOException{
 93         FileInputStream in = new FileInputStream(filePath);
 94         PowerPointExtractor extractor = new PowerPointExtractor(in);
 95         String content = extractor.getText();
 96         extractor.close();
 97         return content;
 98     }
 99     /**
100      * 用来读取pptx文件
101      * @param filePath
102      * @return
103      * @throws IOException
104      */
105     public static String getTextFromPPTX( String filePath) throws IOException{
106         String resultString = null;
107         StringBuilder sb = new StringBuilder();
108         FileInputStream in = new FileInputStream(filePath);
109         try {
110             XMLSlideShow xmlSlideShow = new XMLSlideShow(in);
111             List<XSLFSlide> slides = xmlSlideShow.getSlides();
112             for(XSLFSlide slide:slides){
113                 CTSlide rawSlide = slide.getXmlObject();
114                 CTGroupShape gs = rawSlide.getCSld().getSpTree();
115                 CTShape[] shapes = gs.getSpArray();
116                 for(CTShape shape:shapes){
117                     CTTextBody tb = shape.getTxBody();
118                     if(null==tb){
119                         continue;
120                     }
121                     CTTextParagraph[] paras = tb.getPArray();
122                     for(CTTextParagraph textParagraph:paras){
123                         CTRegularTextRun[] textRuns = textParagraph.getRArray();
124                         for(CTRegularTextRun textRun:textRuns){
125                             sb.append(textRun.getT());
126                         }
127                     }
128                 }
129             }
130             resultString = sb.toString();
131             xmlSlideShow.close();
132         } catch (Exception e) {
133             e.printStackTrace();
134         }
135         return resultString;
136     }
137     /**
138      * 用来读取xls
139      * @param filePath
140      * @return
141      * @throws IOException
142      */
143     public static String getTextFromxls(String filePath) throws IOException{
144         FileInputStream in = new FileInputStream(filePath);
145         StringBuilder content = new StringBuilder();
146         HSSFWorkbook workbook = new HSSFWorkbook(in);
147         for(int sheetIndex=0;sheetIndex<workbook.getNumberOfSheets();sheetIndex++){
148             HSSFSheet sheet = workbook.getSheetAt(sheetIndex);
149             for(int rowIndex=0;rowIndex<=sheet.getLastRowNum();rowIndex++){
150                 HSSFRow row = sheet.getRow(rowIndex);
151                 if(row==null){
152                     continue;
153                 }
154                 for(int cellnum=0;cellnum<row.getLastCellNum();cellnum++){
155                     HSSFCell cell = row.getCell(cellnum);
156                     if(cell!=null){
157                         content.append(cell.getRichStringCellValue().getString()+" ");
158                     }
159                         
160                 }
161             }
162             
163         }
164         workbook.close();
165         return content.toString();
166         
167     }
168     /**
169      * 用来读取xlsx文件
170      * @param filePath
171      * @return
172      * @throws IOException
173      */
174     public static String getTextFromxlsx(String filePath) throws IOException{
175         StringBuilder content = new StringBuilder();
176         XSSFWorkbook workbook = new XSSFWorkbook(filePath);
177         for(int sheet=0;sheet<workbook.getNumberOfSheets();sheet++){
178             if(null!=workbook.getSheetAt(sheet)){
179                 XSSFSheet aSheet =workbook.getSheetAt(sheet);
180                 for(int row=0;row<=aSheet.getLastRowNum();row++){
181                     if(null!=aSheet.getRow(row)){
182                         XSSFRow aRow = aSheet.getRow(row);
183                         for(int cell=0;cell<aRow.getLastCellNum();cell++){
184                             if(null!=aRow.getCell(cell)){
185                                 XSSFCell aCell = aRow.getCell(cell);
186                                 if(convertCell(aCell).length()>0){
187                                     content.append(convertCell(aCell));
188                                 }
189                             }
190                             content.append(" ");
191                         }
192                     }
193                 }
194             }
195         }
196         workbook.close();
197         return content.toString();
198         
199     }
200     
201     private static String convertCell(Cell cell){
202         NumberFormat formater = NumberFormat.getInstance();
203         formater.setGroupingUsed(false);
204         String cellValue="";
205         if(cell==null){
206             return cellValue;
207         }
208         
209         switch(cell.getCellType()){
210             case HSSFCell.CELL_TYPE_NUMERIC:
211                 cellValue = formater.format(cell.getNumericCellValue());
212                 break;
213             case HSSFCell.CELL_TYPE_STRING:
214                 cellValue = cell.getStringCellValue();
215                 break;
216             case HSSFCell.CELL_TYPE_BLANK:
217                 cellValue = cell.getStringCellValue();
218                 break;
219             case HSSFCell.CELL_TYPE_BOOLEAN:
220                 cellValue = Boolean.valueOf(cell.getBooleanCellValue()).toString();
221                 break;
222             case HSSFCell.CELL_TYPE_ERROR:
223                 cellValue = String.valueOf(cell.getErrorCellValue());
224                 break;
225             default:cellValue="";
226         }
227         return cellValue.trim();
228     }
229 }

 

 解释的话就没有那么多时间,这些代码在我的项目中完全正确,所以你们可以放心使用。


以上是关于纯js判断文件流格式类型:pdf,doc,docx,xls,xlsx,ppt,pptx一次搞定!的主要内容,如果未能解决你的问题,请参考以下文章

如何用纯java代码实现word转pdf?

如何用纯java代码实现word转pdf

antd upload上传格式.doc.docx.pdf.png.jpg.rar和大小100兆限制

用java读取多种文件格式的文件(pdf,pptx,ppt,doc,docx..)

如何将word 文件.docx转成.PDF文件

怎么在Linux命令行下转换doc文件到pdf格式