前言
说出来你可能不信,最近经常用excel写代码,经过image2lcd批量处理的图片资源,再往回读就没有批量的工具链了,但又没有到非得写一个工具的程度,所以利用一些shell命令,比如tree获得目录下所有文件,就能直接导入到excel里,现在excel能识别换行,把下一行的内容放到下面的表格上,然后用LEFT或者RIGHT来处理字符串,再用&来拼凑,无论include还是extern,都非常简便,对非序列的资源特别友好。
很多年前,我还在做仓库管理的时候,就想做excel格式的解码,因为从oa上导出的表格,需要经过许多处理才能成为能用的原始数据,再导回oa,又需要按照给定的格式重新编造表格,导入模块做得又特别烂,只是insert,根本就不是update,就想自己写导入导出,甚至可以做一版简易的管理系统。
要做这些,excel的文件解码是绕不过的,excel有两种文件格式,一种是2003以前支持的xls,一种是之后支持的xlsx,从复杂度上说,xls显然更简单一些,但是xls巨量的宏病毒当年就让我疲于奔命,所以打算从xlsx开始。
XLSX格式
xlsx格式核心用xml来描述表结构、表格式、表数据,然后用zip来压缩。所以要解码xlsx格式,需要先解码zip格式。
ZIP文件结构
一个完整的ZIP文件总体是这样的
[local file header 1]
[file data 1]
[data descriptor 1]
.
.
.
[local file header n]
[file data n]
[data descriptor n]
[archive decryption header] (EFS)
[archive extra data record] (EFS)
[central directory]
[zip64 end of central directory record]
[zip64 end of central directory locator]
[end of central directory record]
主要由3类数据组成
压缩文件数据区 | EFS | 压缩文件目录区 | 压缩文件结束标志 | |
---|---|---|---|---|
组成 | local files header(0x04034b50)、files data、data decriptor | archive decryption header、archive extra data record(0x08064b50) | central directory(0x02014b50)、digital signature(0x05054b50)、zip64 end of central directory record(0x06064b50)、zip64 end of central directory locator(0x07064b50) | end of central directory record(0x06054b50) |
1.压缩源文件数据区
压缩源文件区用来记录被打包前的文件的信息,以记录的形式组织,每一个文件或目录(在FAT中,目录就是特殊的文件记录)对应一条记录
源文件记录结构
part1 | part2 | part3 |
---|---|---|
文件头 | 文件数据 | 数据描述 |
local file header | file data | data descriptor |
①.文件头结构(local file header )
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | local file header signature | 文件头标记 | 4 | 0x04034b50 |
0x4 | version needed to extract | 解压文件所需 pkware 版本 | 2 | |
0x6 | general purpose bit flag | 全局方式位标记 | 2 | |
0x8 | compression method | 压缩方式 | 2 | |
0xa | last mod file time | 最后修改文件时间 | 2 | |
0xc | last mod file date | 最后修改文件日期 | 2 | |
0xe | crc-32 | CRC-32校验 | 4 | |
0x12 | compressed size | 压缩后尺寸 | 4 | |
0x16 | uncompressed size | 未压缩尺寸 | 4 | |
0x1a | file name length | 文件名长度 | 2 | |
0x1c | extra field length | 扩展记录长度 | 2 | |
- | file name | 文件名 | (不定长度) | 取决于扩展记录长度 |
- | extra field | 扩展字段 | (不定长度) | 取决于扩展记录长度 |
②.文件数据(file data)
跟在文件头后,文件的压缩或者存储数据
③.数据描述符结构(data descriptor)
这个部分是否存在取决于文件头0x6的全局方式位标记的第三位是否置位。
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | crc-32 | CRC-32校验 | 4 | |
0x4 | compressed size | 压缩后尺寸 | 4 | |
0x8 | uncompressed size | 未压缩尺寸 | 4 |
EFS
6.2版本中引入的格式规范
Archive extra data record: (EFS)
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | archive extra data signature | 4 | (0x08064b50) | |
0x4 | extra field length | 4 | ||
0x8 | extra field data | (variable size) |
2.压缩源文件目录区
该区由三个部分组成
part1 | part2 | part3 |
---|---|---|
0x02014b50、0x05054b50 | 0x06064b50 | 0x07064b50 |
central directory | zip64 end of central directory record | zip64 end of central directory locator |
①.central directory
由两个部分组成,file header和 digital signature。
[file header 1]
.
.
.
[file header n]
[digital signature]
Ⅰ.file header结构
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | central file header signature | 目录中文件文件头标记 | 4 | 0x02014b50 |
0x4 | version made by | 压缩使用的 pkware 版本 | 2 | |
0x6 | version needed to extract | 解压文件所需 pkware 版本 | 2 | |
0x8 | general purpose bit flag | 全局方式位标记 | 2 | |
0xa | compression method | 压缩方式 | 2 | |
0xc | last mod file time | 最后修改文件时间 | 2 | |
0xe | last mod file date | 最后修改文件日期 | 2 | |
0x10 | crc-32 | CRC-32校验 | 4 | |
0x14 | compressed size | 压缩后尺寸 | 4 | |
0x18 | uncompressed size | 未压缩尺寸 | 4 | |
0x1c | file name length | 文件名长度 | 2 | |
0x1e | extra field length | 扩展字段长度 | 2 | |
0x20 | file comment length | 文件注释长度 | 2 | |
0x22 | disk number start | 磁盘开始号 | 2 | |
0x24 | internal file attributes | 内部文件属性 | 2 | |
0x26 | external file attributes | 外部文件属性 | 4 | |
0x2a | relative offset of local header | 局部头部偏移量 | 4 | |
- | file name | 文件名 | (不定长度) | 取决于扩展记录长度 |
- | extra field | 扩展字段 | (不定长度) | 取决于扩展记录长度 |
- | file comment | 文件注释 | (不定长度) | 取决于扩展记录长度 |
Ⅱ.digital signature结构
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | header signature | 文件头标记 | 4 | 0x05054b50 |
0x4 | size of data | 数据大小 | 2 | |
0x6 | signature data | 数据 | (不定长度) | 取决于数据大小 |
②.Zip64 end of central directory record
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | zip64 end of central dir signature | 4 | (0x06064b50) | |
0x4 | size of zip64 end of central directory record | 8 | ||
0xc | version made by | 2 | ||
0xe | version needed to extract | 2 | ||
0x10 | number of this disk | 4 | ||
0x14 | number of the disk with the start of the central directory | 4 | ||
0x18 | total number of entries in the central directory on this disk | 8 | ||
0x20 | total number of entries in the central directory | 8 | ||
0x28 | size of the central directory | 8 | ||
0x30 | offset of start of central directory with respect to the starting disk number | 8 | ||
0x38 | zip64 extensible data sector | (variable size) |
③.Zip64 end of central directory locator
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | zip64 end of central dir locator signature | 4 | (0x07064b50) | |
0x4 | number of the disk with the start of the zip64 end of central directory | 4 | ||
0x8 | relative offset of the zip64 end of central directory record | 8 | ||
0x10 | total number of disks | 4 |
3.压缩源文件目录结束标志
offset | name | 作用 | 长度(字节) | 注解 |
---|---|---|---|---|
0x0 | end of central dir signature | 目录结束标记 | 4 | 0x06054b50 |
0x4 | number of this disk | 当前磁盘编号 | 2 | |
0x6 | number of the disk with the start of the central directory | 目录区开始磁盘编号 | 2 | |
0x8 | total number of entries in the central directory on this disk | 本磁盘上纪录总数 | 2 | |
0xa | total number of entries in the central directory | 目录区中纪录总数 | 2 | |
0xc | size of the central directory | 目录区尺寸大小 | 4 | |
0x10 | offset of start of central directory with respect to the starting disk number | 目录区对第一张磁盘的偏移量 | 4 | |
0x14 | .ZIP file comment length | ZIP 文件注释长度 | 2 | |
0x16 | .ZIP file comment | ZIP 文件注释 | 不定长度 |