复合文档格式研究之06-读取Directory

李懿 Excel学习 2016-07-05

微信扫一扫
关注该公众号

6、读取Directory

终于离破解只剩2步了,我们先来看倒数第二步。

6.1 Directory Entry

Directory Entry是一个记录了复合文档中的所有内容的目录。它的数据结构是一个红黑树,我们不必管这是个啥玩意儿,反正在这篇教程中也用不着。Directory Entry的长度为128个字节,它记录的信息如下:  
    
 26         Directory Entry结构

Directory Entry NameDirectory
Entry的名称,总长度为64个字节,是一个双字节的UNICODE字符类型,可以用StrConv函数进行转换。

Name Length记录了名称的长度。2字节。

TypeEntry的类型。1字节。

            0代表非法,

            1代表Storage,

            2代表Stream,

            5代表Root Entry(即第一个目录内容)。

Color节点的颜色。1字节。

Left Sibling ID左兄弟节点ID。4字节。

Right Sibling ID右兄弟节点ID。4字节。

Child ID子节点ID。4字节。

CLSID没啥用,一般都是0。16字节。

State Bits没啥用,一般都是0。4字节。

Creation Time创建时间,这个挺复杂,不介绍如何解析了。8字节。

Modify Time修改时间,这个挺复杂,不介绍如何解析了。8字节。

Start Sector Location若是Stream类型,则表示数据扇区的起始ID。4字节。

Stream SizeStream的大小。LONGLONG的类型,8个字节。其实只用4个。这个属性决定了数据存储在一般的扇区还是mini扇区。当大小大于或等于4096的时候,数据存放在普通扇区,其余的存放在mini扇区。

6.2 StorageStream

你应该注意到了有两种类型的Directory Entry,它们是Storage和Stream。这两者的关系就和文件夹以及文件一样。Storage是文件夹,把Stream合并归类,而Stream则是实际的文件了,所有的Stream都有相应的扇区存储数据。

6.3 VBA读取Directory Entry

经过前面那么多的代码的熏陶,相信你已经掌握了基本的方法了吧。我们再来总结一下:

  • 声明一个自定义类型来表示Directory Entry数据

  • 按照文件头的信息读取第一个Directory Entry扇区

  • 按照FAT表按顺序读取剩下的Directory Entry扇区

我们来看下核心代码:

Sub ReadDir(FS As Integer, FAT() As Long, DirEntry() As CFBDirecroty, SectorID As Long, SectorSize As Long)

   Dim i       As Long

   Dim Entry   As CFBDirecroty

   '若SectorID为结束ID,则停止读取

   If SectorID = SECTORTYPE.ENDOFCHAIN Or SectorID = SECTORTYPE.FREESECT Then

        Exit Sub

   End If

   '定位

   Seek FS, GetFileOffset(SectorID, SectorSize)

   For i = 1 To SectorSize / 128

        '读取数据

        Get FS, , Entry

        '添加元素

        AddDir2List DirEntry(), Entry

   Next i

   '读取下一个Sector

   ReadDir FS, FAT(), DirEntry(), FAT(SectorID), SectorSize

End Sub

是不是很简单啊,思路完全一样。(此处省略Directory Entry的类型声明)

6.4 改进的Directory Entry结构

读完上述Directory Entry信息之后,起始我们发现有很多信息是没用的,而且Entry的名称也不太好读。


 27         Directory Entry原始信息

那些个方块实在不咋滴。

我们来改进下吧,再声明一个自定义类型,把需要的信息存放进去。

Public Type DirectoryEntryLocal

   EntryName               As String       '名称

   EntryType               As EntryType    '类型

   LeftSiblingID           As Long         '左兄弟节点ID

   RightSiblingID          As Long         '右兄弟节点ID

   ChildID                 As Long         '子节点ID

   SectorStartID           As Long         '若是Stream,数据起始扇区ID

   StreamSize              As Long         'Stream的大小

End Type

再来改一下原来的代码

Sub ReadDirLocal(FS As Integer,FAT() As Long, DirEntry() As DirectoryEntryLocal, SectorID As Long,SectorSize As Long)

   Dim i           As Long

   Dim Entry       As CFBDirecroty

   Dim EntryLocal  As DirectoryEntryLocal

   '若SectorID为结束ID,则停止读取

   If SectorID = SECTORTYPE.ENDOFCHAIN Or SectorID = SECTORTYPE.FREESECT Then

        Exit Sub

   End If

   '定位

   Seek FS, GetFileOffset(SectorID, SectorSize)

   For i = 1 To SectorSize / 128

        '读取数据

        Get FS, , Entry

        If Entry.ENTRYTYPE <> ENTRYTYPE.dirNA Then

            EntryLocal.EntryName = StrConv(Left(Entry.EntryName, Entry.EntryLength - 2), vbFromUnicode)

            EntryLocal.ENTRYTYPE = Entry.ENTRYTYPE

            EntryLocal.ChildID = Entry.ChildID

            EntryLocal.LeftSiblingID = Entry.LeftSiblingID

            EntryLocal.RightSiblingID = Entry.RightSiblingID

            EntryLocal.SectorStartID = Entry.SectorStartID

            EntryLocal.StreamSize = Entry.StreamSize(0)

            '添加元素

            AddDirLocal2List DirEntry(),EntryLocal

        End If

    Next i

    '读取下一个Sector

    ReadDirLocal FS, FAT(), DirEntry(), FAT(SectorID), SectorSize

End Sub

运行一下程序,看看结果


28         进的Directory Entry

这样一看,是不是爽快多了啊,哈哈。感兴趣的可以看下每个DirLocal下的内容。

6.5 小结

如果你一路都跟着我的节奏,并且自己写代码操练的话,相信你已经掌握了解析复合文档的方法了。接下去的事情基本都是重复的了,我们将在下一章简单介绍一下VBA部分。

这次有点福利,下面是我写了这么多的参考文档,也发给大家,都是微软官方公布的。后面的一个链接还有一个官方提供的工具,但是结果是错的,不知道是存心唬弄人还是咋的。但是我们都做对了,是不是很有成就感啊。哈哈。


29         官方工具和自制程序对比

 

参考文档:

Compound File Binary File Format:

https://msdn.microsoft.com/en-us/library/dd942138.aspx

Understanding the Excel .xls Binary File
Format(本文中提供了一个工具可以查看二进制复合文件,但是解析Directory的部分是错的)

https://msdn.microsoft.com/zh-cn/library/office/gg615597(v=office.14).aspx

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值