枚举复合文件的存储结构

    技术2022-05-11  15

    枚举复合文件的存储结构      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();    }} 


    最新回复(0)