Chinaunix首页 | 论坛 | 博客
  • 博客访问: 19279275
  • 博文数量: 7460
  • 博客积分: 10434
  • 博客等级: 上将
  • 技术积分: 78178
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-02 22:54
文章分类

全部博文(7460)

文章存档

2011年(1)

2009年(669)

2008年(6790)

分类: C/C++

2008-05-31 08:37:32

Word和Excel等文件均称为复合文件。这类文件内部有一个“文件系统”,采用“磁盘文件”的组织方式来组织文件内的数据,也称为“文件中的文件系统”。
    每个复合文件中有一个“根”(类似于文件系统中的“根目录”),根之下是若干“子存储”(类似于“子目录”)和“数据流”(类似于“文件”),子存储之下可以再有子存储和数据流……。
下列代码可将任一复合文件的文件结构进行枚举,如配合树型控件(如:CTreeCtrl),可将文件的存储结构清晰的展现出来。
#include 

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; [Page]

    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);        // 得到子存储接口指针

[NextPage]


            if (FAILED(hr))
            {
                return;
            } [Page]

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

            break;

        case STGTY_STREAM:    // 数据流

            // ...

            break;
        }

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

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

阅读(363) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~