xlsx/pptx/docx文件数据格式解析-帮你搞懂数据到底存在哪

2023-11-22 07:59

本文主要是介绍xlsx/pptx/docx文件数据格式解析-帮你搞懂数据到底存在哪,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

序言

在开发过程中经常遇到office文件相关的问题,比如将数据导出成Excel、自动生成报表、自动生成填充合同模板、转pdf等。UOffice是一个为解决这类Office文件问题的项目,里面记录了到目前为止,笔者遇到的相关问题的解决方案。笔者希望UOffice能称为一个完善的集合,但是靠一个人很难做到完善,所以这个项目后续会公开到github上,希望能为大家提供便利,也希望大家共同完善功能,使之更加健壮。

(.xlsx、.docx、.pptx)文件解析

.xlsx、.docx、.pptx是ooxml格式的office文件,简单了来说就是(压缩+xml)的格式。也就说你可以用压缩工具(比如7zip)将一个xlsx(或docx、pptx)文件解压。以xlsx为例,其他文件格式类似。
xlsx文件
xlsx内容

xlsx解压完后
下面详细介绍下主要的几个部分的作用。

xl/sharedStrings.xml

此文件主要保本excel中各个单元格文本的内容。

<sst xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" count="2" uniqueCount="2">
<si>
<t>我是</t>
<phoneticPr fontId="1" type="noConversion"/>
</si>
<si>
<t>Uoffice</t>
<phoneticPr fontId="1" type="noConversion"/>
</si>
</sst>

其中内容是去重的,相同的内容只能存一份。count代表总数,uniqueCount是去重后的数量。

xl/styles.xml

此文件主要存单元格的格式信息

<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac">
<fonts count="2" x14ac:knownFonts="1">
<font>
<sz val="11"/>
<color theme="1"/>
<name val="宋体"/>
<charset val="134"/>
<scheme val="minor"/>
</font>
<font>
<sz val="9"/>
<name val="宋体"/>
<charset val="134"/>
<scheme val="minor"/>
</font>
</fonts>
<fills count="2">
<fill>
<patternFill patternType="none"/>
</fill>
<fill>
<patternFill patternType="gray125"/>
</fill>
</fills>
<borders count="1">
<border>
<left/>
<right/>
<top/>
<bottom/>
<diagonal/>
</border>
</borders>
<cellStyleXfs count="1">
<xf numFmtId="0" fontId="0" fillId="0" borderId="0">
<alignment vertical="center"/>
</xf>
</cellStyleXfs>
<cellXfs count="1">
<xf numFmtId="0" fontId="0" fillId="0" borderId="0" xfId="0">
<alignment vertical="center"/>
</xf>
</cellXfs>
<cellStyles count="1">
<cellStyle name="常规" xfId="0" builtinId="0"/>
</cellStyles>
<dxfs count="0"/>
<tableStyles count="0" defaultTableStyle="TableStyleMedium2" defaultPivotStyle="PivotStyleLight16"/>
<extLst>
<ext xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" uri="{EB79DEF2-80B8-43e5-95BD-54CBDDF9020C}">
<x14:slicerStyles defaultSlicerStyle="SlicerStyleLight1"/>
</ext>
<ext xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main" uri="{9260A510-F301-46a8-8635-F512D64BE5F5}">
<x15:timelineStyles defaultTimelineStyle="TimeSlicerStyleLight1"/>
</ext>
</extLst>
</styleSheet>

<fonts/>标签存放了xlsx中的字体信息,<fills/>标签存放了xlsx的单元格填充信息,标签存放了单元格边框信息,最重要的是** <cellXfs> **标签,里面综合了单元格的配置信息。

xl/worksheets/sheet1.xml

此文件中主要存放了每个单元格的具体信息

<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:x14ac="http://schemas.microsoft.com/office/spreadsheetml/2009/9/ac" mc:Ignorable="x14ac">
<dimension ref="A1:B1"/>
<sheetViews>
<sheetView tabSelected="1" workbookViewId="0">
<selection activeCell="B1" sqref="B1"/>
</sheetView>
</sheetViews>
<sheetFormatPr defaultColWidth="9" defaultRowHeight="14.4" x14ac:dyDescent="0.25"/>
<sheetData>
<row r="1" spans="1:2" x14ac:dyDescent="0.25">
<c r="A1" t="s">
<v>0</v>
</c>
<c r="B1" t="s">
<v>1</v>
</c>
</row>
</sheetData>
<phoneticPr fontId="1" type="noConversion"/>
<pageMargins left="0.7" right="0.7" top="0.75" bottom="0.75" header="0.3" footer="0.3"/>
<pageSetup paperSize="9" orientation="portrait"/>
</worksheet>

<sheetData>标签中的row标签代表了每一行,row中的c标签单表了一行中的每一个单元格,c标签中的t="s"表示该单元格为文字,通过v标签标记的索引在sharedStrings.xml中查找。如果c标签中没有t变量,表示单元格为数字,此时v标签内的内容即为单元格内容。c标签中还有一个s变量,s变量指向styles.xml中的cellXfs标签,此处s变量未声明,默认应用cellXfs中的第一个。

总结

ooxml的格式大致如上所示,如果文件中有图像、引用等特殊元素,也是通过不同xml去表示的。
最后放上UOffice中解压文件和聚合文件的代码

protected void initTemplate(InputStream inputStream) {String path = File.separator + UUID.randomUUID().toString();try (ZipInputStream zipInputStream = new ZipInputStream(inputStream)) {ZipEntry nextEntry;while ((nextEntry = zipInputStream.getNextEntry()) != null) {if (nextEntry.isDirectory()) {String tempPath = path + File.separator + nextEntry.getName();File tempFile = new File(tempPath);if (!tempFile.exists()) {if (!tempFile.mkdirs()) {throw new UOfficeException("创建{}失败", tempFile.getAbsolutePath());}}} else {String tempPath = path + File.separator + nextEntry.getName();File tempFile = new File(tempPath);FileOutputStream fileOutputStream = new FileOutputStream(tempFile);byte[] buffer = new byte[1024];int read = 0;while ((read = zipInputStream.read(buffer)) != -1) {fileOutputStream.write(buffer, 0, read);}fileOutputStream.close();}zipInputStream.closeEntry();}templatePath = path;} catch (Exception e) {PathUtils.deleteAllDir(path);}}
public void writeToStream(OutputStream outputStream) {List<PathEntry> pathEntries = PathUtils.pathWalk(templatePath);if (ObjectUtils.isNotEmpty(outputStream)) {try (ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {for (PathEntry p : pathEntries) {ZipEntry zipEntry = new ZipEntry(p.getName());zipOutputStream.putNextEntry(zipEntry);if (!p.isWhetherDir()) {String s = templatePath + File.separator + p.getName();FileInputStream fileInputStream = new FileInputStream(new File(s));byte[] buffer = new byte[1024];int read = 0;while ((read = fileInputStream.read(buffer)) != -1) {zipOutputStream.write(buffer, 0, read);}fileInputStream.close();}zipOutputStream.closeEntry();}} catch (IOException e) {e.printStackTrace();}}}

最后限于本人能力的原因,难免有错误或遗漏之处,请大家多多指正。前两天发起了一个投票“做一个自动填充数据生成xlsx文件功能的价值”,共三人(包括我自己)投票表示很有价值,所以下一篇介绍如何去自动填充数据。

这篇关于xlsx/pptx/docx文件数据格式解析-帮你搞懂数据到底存在哪的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/408671

相关文章

详谈redis跟数据库的数据同步问题

《详谈redis跟数据库的数据同步问题》文章讨论了在Redis和数据库数据一致性问题上的解决方案,主要比较了先更新Redis缓存再更新数据库和先更新数据库再更新Redis缓存两种方案,文章指出,删除R... 目录一、Redis 数据库数据一致性的解决方案1.1、更新Redis缓存、删除Redis缓存的区别二

Redis事务与数据持久化方式

《Redis事务与数据持久化方式》该文档主要介绍了Redis事务和持久化机制,事务通过将多个命令打包执行,而持久化则通过快照(RDB)和追加式文件(AOF)两种方式将内存数据保存到磁盘,以防止数据丢失... 目录一、Redis 事务1.1 事务本质1.2 数据库事务与redis事务1.2.1 数据库事务1.

python 字典d[k]中key不存在的解决方案

《python字典d[k]中key不存在的解决方案》本文主要介绍了在Python中处理字典键不存在时获取默认值的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,... 目录defaultdict:处理找不到的键的一个选择特殊方法__missing__有时候为了方便起见,

Oracle Expdp按条件导出指定表数据的方法实例

《OracleExpdp按条件导出指定表数据的方法实例》:本文主要介绍Oracle的expdp数据泵方式导出特定机构和时间范围的数据,并通过parfile文件进行条件限制和配置,文中通过代码介绍... 目录1.场景描述 2.方案分析3.实验验证 3.1 parfile文件3.2 expdp命令导出4.总结

更改docker默认数据目录的方法步骤

《更改docker默认数据目录的方法步骤》本文主要介绍了更改docker默认数据目录的方法步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1.查看docker是否存在并停止该服务2.挂载镜像并安装rsync便于备份3.取消挂载备份和迁

不删数据还能合并磁盘? 让电脑C盘D盘合并并保留数据的技巧

《不删数据还能合并磁盘?让电脑C盘D盘合并并保留数据的技巧》在Windows操作系统中,合并C盘和D盘是一个相对复杂的任务,尤其是当你不希望删除其中的数据时,幸运的是,有几种方法可以实现这一目标且在... 在电脑生产时,制造商常为C盘分配较小的磁盘空间,以确保软件在运行过程中不会出现磁盘空间不足的问题。但在

在C#中合并和解析相对路径方式

《在C#中合并和解析相对路径方式》Path类提供了几个用于操作文件路径的静态方法,其中包括Combine方法和GetFullPath方法,Combine方法将两个路径合并在一起,但不会解析包含相对元素... 目录C#合并和解析相对路径System.IO.Path类幸运的是总结C#合并和解析相对路径对于 C

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

一文带你搞懂Nginx中的配置文件

《一文带你搞懂Nginx中的配置文件》Nginx(发音为“engine-x”)是一款高性能的Web服务器、反向代理服务器和负载均衡器,广泛应用于全球各类网站和应用中,下面就跟随小编一起来了解下如何... 目录摘要一、Nginx 配置文件结构概述二、全局配置(Global Configuration)1. w

Java解析JSON的六种方案

《Java解析JSON的六种方案》这篇文章介绍了6种JSON解析方案,包括Jackson、Gson、FastJSON、JsonPath、、手动解析,分别阐述了它们的功能特点、代码示例、高级功能、优缺点... 目录前言1. 使用 Jackson:业界标配功能特点代码示例高级功能优缺点2. 使用 Gson:轻量