VBA解析复合文档05——读取数据流

时间:2022-07-22
本文章向大家介绍VBA解析复合文档05——读取数据流,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

根据前面解析得到的FAT数组、MiniFAT数组、目录信息,读取某个数据流就很简单了,只需要根据FAT数组或者MiniFAT数组构建的扇区链表,逐个扇区的去读取就可以:


'读取某个数据流
'dir_name   需要读取的文件名称,是复合文档中的文件名称
'RetBytes   返回解压后的数据Byte数组
'Return     返回出错信息
Function GetStream(dir_name As String, RetBytes() As Byte) As String
    If cf.h.Exists(dir_name) Then
        GetStream = GetStreamByDirIndex(VBA.CLng(cf.h.GetItem(dir_name)), RetBytes)
    Else
        GetStream = "复合文档:不存在的目录"
        Exit Function
    End If
End Function
'读取数据流
Private Function GetStreamByDirIndex(dirIndex As Long, RetBytes() As Byte) As String
    '1仓storage 2流 5根
    If cf.ArrDir(dirIndex).ObjectType <> 2 Then
        GetStreamByDirIndex = "复合文档:不是数据流"
        Exit Function
    End If
    If cf.ArrDir(dirIndex).StartingSectorID = Free_SID Then
        GetStreamByDirIndex = "复合文档:流的大小为0"
        Exit Function
    End If
    
    ReDim RetBytes(cf.ArrDir(dirIndex).StreamSize - 1) As Byte
    If cf.ArrDir(dirIndex).StreamSize < cf.Header.MiniStreamSize Then
        GetStreamByDirIndex = GetStreamMiniFAT(dirIndex, RetBytes)
    Else
        GetStreamByDirIndex = GetStreamFAT(dirIndex, RetBytes)
    End If
    
End Function

'按照FAT读取数据
Private Function GetStreamFAT(dirIndex As Long, RetBytes() As Byte) As String
    Dim b() As Byte
    ReDim b(cf.lSectorSize - 1) As Byte
    
    '找到读取开始的位置
    Dim sid As Long
    sid = cf.ArrDir(dirIndex).StartingSectorID
    
    Dim i As Long
    Dim p As Long
    
    Do
        '设置读取的位置
        cf.r.SeekFile getOffsetBySID(sid), OriginF
        
        cf.r.Read b
        For i = 0 To cf.lSectorSize - 1
            RetBytes(p) = b(i)
            p = p + 1
            If p = cf.ArrDir(dirIndex).StreamSize Then Exit Function
        Next
        
        '下一个扇区
        sid = cf.FAT(sid)
    Loop
    
End Function

'按照MiniFAT读取数据
Private Function GetStreamMiniFAT(dirIndex As Long, RetBytes() As Byte) As String
    Dim b() As Byte
    ReDim b(cf.lShortSectorSize - 1) As Byte
    
    '找到读取开始的位置
    Dim miniSID As Long
    miniSID = cf.ArrDir(dirIndex).StartingSectorID
    
    Dim i As Long
    Dim p As Long
    
    Do Until miniSID = End_Of_Chain_SID
        '设置读取的位置
        cf.r.SeekFile getOffsetByMiniFATSID(miniSID), OriginF
        
        cf.r.Read b
        For i = 0 To cf.lShortSectorSize - 1
            RetBytes(p) = b(i)
            p = p + 1
            If p = cf.ArrDir(dirIndex).StreamSize Then Exit Do
        Next
        
        '下一个扇区
        miniSID = cf.MiniFAT(miniSID)
    Loop
End Function