枚举复合文件的存储结构

本文介绍了一种方法,用于解析Word和Excel等复合文件的内部结构,并提供了一个C++示例代码,展示了如何枚举这些文件中的子存储和数据流。

Word和Excel等文件均称为复合文件。这类文件内部有一个“文件系统”,采用“磁盘文件”的组织方式来组织文件内的数据,也称为“文件中的文件系统”。

每个复合文件中有一个“根存储”(类似于文件系统中的“根目录”),根存储之下是若干“子存储”(类似于“子目录”)和“数据流”(类似于“文件”),子存储之下可以再有子存储和数据流……。

下列代码可将任一复合文件的文件结构进行枚举,如配合树型控件(如:CTreeCtrl),可将文件的存储结构清晰的展现出来。

#include <atlconv.h>

void DocFileViewer(LPCTSTR lpszPathName) 
{
    
// lpszPathName: 复合文件存储路径

    
// COM 初始化
    
// 如果是MFC程序,可以使用AfxOleInit()替代
    ::CoInitialize(NULL);

    USES_CONVERSION;

    LPCTSTR lpFileName 
= lpszPathName;
    HRESULT hr;
    IStorage 
* pStg = NULL;
    
    LPCOLESTR lpwFileName 
= T2COLE(lpFileName);    // 转换T类型为宽字符
    hr = ::StgIsStorageFile(lpwFileName);        // 是复合文件吗?
    if (FAILED(hr))
    {
        
return FALSE;
    }
    hr 
= ::StgOpenStorage(        // 打开复合文件
        lpwFileName,        // 文件名称
        NULL,
        STGM_READWRITE 
| STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
        
0,
        
0,
        
&pStg);            // 得到根存储接口指针

    EnumStorage(pStg);        
// 开始枚举

    
if (pStg)
    {
        pStg
->Release();
    }

    
// COM 释放
    
// 如果使用了AfxOleInit(),则无需调用该函数
    ::CoUninitialize();
}

void EnumStorage(IStorage *pStg)
{
    USES_CONVERSION;

    IEnumSTATSTG 
* pEnum = NULL;    // 枚举器
    HRESULT hr;

    hr 
= pStg->EnumElements(0, NULL, 0&pEnum);
    ASSERT(SUCCEEDED(hr));

    STATSTG statstg;
    IStorage 
* pStgSub = NULL;    // 子存储接口指针

    
while (pEnum->Next(1&statstg, NULL) == NOERROR)
    {
        
// statstg.type 保存着对象类型 STGTY_STREAM 或 STGTY_STORAGE
        
// statstg.pwcsName 保存着对象名称
        
// ...... 还有时间,长度等很多信息。请查看 MSDN

        
switch (statstg.type)
        {
        
case STGTY_STORAGE:    // 子存储

            
// ...

            hr 
= pStg->OpenStorage(        // 打开子存储
                statstg.pwcsName,
                NULL,
                STGM_READWRITE 
| STGM_DIRECT | STGM_SHARE_EXCLUSIVE,
                NULL,
                
0,
                
&pStgSub);        // 得到子存储接口指针

            
if (FAILED(hr))
            {
                
return;
            }

            EnumStorage(pStgSub);        
// 递归枚举子存储

            
break;

        
case STGTY_STREAM:    // 数据流

            
// ...

            
break;
        }

        ::CoTaskMemFree(statstg.pwcsName);    
// 释放名称所使用的内存
    }
    
    
if (pEnum)
    {
        pEnum
->Release();
    }

    
if (pStgSub)
    {
        pStgSub
->Release();
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值