自从Windows系统推出以后,微软公司就一直致力于完善和采用新的文件存储方法,其中结构化存储是微软公司最为推崇的,该技术采用COM技术架构,当前广泛使用的Office文
|
所谓结构化存储方法,实际是把树状文件系统的原理应用到单个的文件中,使得单个文件也能象文件系统一样包含"子目录","子目录"还可以包含更深层次的"子目录",各个"目录"可以含多个文件,把原来需要多个文件存储的内容按树状结构和层次保存到一个文件中去。对清楚磁盘存储的用户来说,很容易理解这种存储方法可以极大程度的提高磁盘空间使用效率。另外便于在单个文件就能明确内容的归属关系和分类关系,再就是在软件分发过程不需要带一大批的分发文件,可以把数据文件归结到一个文件中去。
本文将阐述Windows提供的结构化存储的相关技术,并且用Delphi语言加以应用实现。
一、结构化存储技术介绍
在Windows SDK中详细介绍了结构化存储的各个相关的知识,上面已经讲到该技术采用Com架构,所以提供的函数都用到接口,其中IStorage、Istream、IEnumSTATSTG是三个最重要的结构化存储接口(Interface)。
1、IStorage
IStorage接口支持结构化存储文件创建和结构化文件管理的相关功能。它可以包含其它的多个IStorage,相当于文件系统中的"子目录",也可以包含下面要阐述的多个Istream,相当于文件系统的具体"单个文件"。一个结构化存储的文件可以用下图来表示它的结构。
从上图我们可以看到任何一个结构化存储文件都存在一个根IStorage,在该接口下面可以包含多个一级子IStorage,一级子IStorage下可以包含多个二级子IStorage,依次延续,就形成了结构化存储文件的层次和树状结构,而每个IStorage下面可以含任意个Istream即相当与文件系统中具体的单个文件。
关于IStorage的主要函数有:
1.1 StgCreateDocfile
该函数创建一个结构化存储的文件,并且返回IStorage接口,其函数格式为:HRESULT StgCreateDocfile(
const WCHAR * pwcsName, //要创建的结构化存储文件名
DWORD grfMode, //结构化存储文件的访问模式
DWORD reserved, //保留,必须为零
IStorage ** ppstgOpen //返回的IStorage接口变量
);
1.2 StgOpenStorage
该函数打开一个结构化存储的文件,并且返回IStorage借口,起函数格式为:HRESULT StgOpenStorage(
const WCHAR * pwcsName, //要打开的结构化存储文件
IStorage * pstgPriority, //以前打开的IStorage 一般为nil
DWORD grfMode, //文件打开的模式
SNB snbExclude, //代表SNB结构,可以为nil
DWORD reserved, //保留,必须为0
IStorage ** ppstgOpen //返回的IStorage接口变量
);
1.3 StgIsStorageFile
该函数判断指定文件是否是按照结构化方式存储。其函数格式为:
HRESULT StgIsStorageFile(
const WCHAR * pwcsName //需要判断的文件名
);
1.4 CreateStorage
该函数是IStorage接口提供的函数,它为IStorage创建一个下一个层次的IStorage,也即相当于创建"子目录"。其函数格式为:
HRESULT CreateStorage(
const wchar_t * pwcsName, //要创建的"子"IStorage的名称
DWORD grfMode, //"子"Istorage的访问模式
DWORD reserved1, //保留,必须为零
DWORD reserved2, //保留,必须为零
IStorage ** ppstg //返回的IStorage接口变量
);
1.5 CreateStream
该函数是IStorage接口提供的函数,它为IStorage创建一个下属的IStream,也即相当于创建单个具体"文件"。其函数格式为:
HRESULT CreateStream(
const wchar_t * pwcsName, //要创建"子"Istream的名称
DWORD grfMode, //"子"IStream的访问模式
DWORD reserved1, //保留,必须为零
DWORD reserved2, //保留,必须为零
IStream ** ppstm //返回的IStream接口变量
);
1.6 OpenStorage
该函数是IStorage接口提供的函数,打开当前IStorage的子IStorage,其函数格式为:
HRESULT OpenStorage(
const wchar_t * pwcsName, //子IStorage名
IStorage * pstgPriority, //以前打开的IStorage 一般为nil
DWORD grfMode, //打开IStorage的访问模式
SNB snbExclude, //SNB模块,一般为nil
DWORD reserved, //保留,必须为零
IStorage ** ppstg //返回的IStorage接口变量
);
1.7 OpenStream
该函数是IStorage接口提供的函数,打开当前IStorage的子IStream,其函数格式为:
HRESULT OpenStream(
const wchar_t * pwcsName, //要打开的IStream名
void * reserved1, //保留,必须为nil
DWORD grfMode, //打开的Istream访问模式
DWORD reserved2, //保留,必须为零
IStream ** ppstm //返回的IStream接口变量
);
1.8 EnumElements
该函数是IStorage接口提供的函数,获取IStorage内含内容的枚举IEnumSTATSTG接口,通过IEnumSTATSTG可以获取结构化存储文件的树状和层次结构。关于IEnumSTATSTG在后面将再作介绍,其函数格式为:
HRESULT EnumElements(
DWORD reserved1, //保留,必须为零
void * reserved2, //保留,必须为nil
DWORD reserved3, //保留,必须为0
IEnumSTATSTG ** ppenum //返回的IEnumSTATSTG接口变量
);
1.9 MoveElementTo
该函数是IStorage接口提供的函数,把IStorage下的"子"IStorage或者"子"IStream进行移动或者复制。其函数格式为:
HRESULT MoveElementTo(
const wchar_t pwcsName, //要移动或复制的IStorage、Istream名
IStorage * pstgDest, //要移动或复制到目标IStorage的名
LPWSTR pwcsNewName, //移动或复制到新"目的地"后的名称
DWORD grfFlags //标志是移动还是复制
);
1.10 RenameElement、DestroyElement
该函数是IStorage接口提供的函数,对IStorage进行重新命名和删除。其函数格式略。
关于IStorage接口还提供了其它的一些函数,需要更加详细地了解可以参考Windows SDK API的相关函数。
2、IStream
IStream接口是嵌套在IStorage中,其主要功能是具体实现从结构化存储文件读取数据,同时实现向结构化存储文件中写数据。该接口提供的函数主要有以下几个:
2.1
HRESULT Read(
void * pv, //数据读取出来存放到变量
ULONG cb, //需要读取的字节数
ULONG * pcbRead //实际读取的字节数
);
2.2 Write,向IStream中写入数据,其函数格式为:
HRESULT Write(
void const* pv, //要写入数据的常量
ULONG cb, //需要写入的字节数
ULONG * pcbWritten //实际写入的字节数
);
2.3 Seek,移动读写的文件指针,其函数格式为:
HRESULT Seek(
LARGE_INTEGER dlibMove, //文件指针移动的字节数
DWORD dwOrigin, //文件指针从那个位置进行字节移动
ULARGE_INTEGER * plibNewPosition //新指针位置可以为nil
);
3、IEnumSTATSTG
IEnumStatSTG接口是实现对结构化存储文件的树状浏览,其函数相对简单主要有以下三个:
HRESULT Next(ULONG celt, STATSTG * rgelt, ULONG * pceltFetched)
HRESULT Skip(ULONG celt)
HRESULT Reset(void)
二、Delphi中应用结构化存储的几个要点
1、结构化存储技术是采用COM的技术架构,它的应用相对于常用的存储技术有一定差异。在Delphi语言中对流(Stream)的操作都是基于Tstream派生出来,象TFileStream、TMemoryStream等等都是Tstream的子类,而Delphi提供的具有相当好操作性的Treader和Twriter都是和Tstream类相对应操作的。为保持Delphi语言应用的一贯性和相互融通,Delphi语言特别提供了一个Tstream派生类TOLEStream,它专门用于针对IStream接口的相关操作。TOLEStream的构造函数为:Constructor Create(const Stream: IStream);虽然通过IStorage和IStream可以实现结构化存储技术进行文件的存取,但本人建议Delphi语言开发中最好通过TOLEStream实现结构化存储文件的存取工作。TOLEStream在Axctrls.pas中实现。
2、Delphi语言为方便开发人员,把结构化存储技术的相关函数和接口都进行封装,统一在Activex.pas单元中加以引用实现,所以要引用上述的IStorage、IStream以及相关的函数要把Activex做为引用单元。
3、关于IStorage和IStream相关函数的返回值都是Hresult,如果函数运行正常一般返回值为S_OK,为检验返回值是否正确可以调用OLECheck函数,如果IStorage和IStream相关函数返回的信息是错误的话,OLECheck将"引发" EoleSysError类的错误供开发人员调试和运行中检测。OLECheck函数封装在ComOBJ.pas单元中。
4、一般情况下,任何一个对象有创建就有释放相对应,但IStorage和IStream不需要人工释放,系统将会根据这两个接口的引用"计数器"是否为零自动释放,所以不要调用IStorage.release或IStream.release。
三、结构化存储技术应用举例
有了上面的知识以后,就可以把结构化存储技术运用到我们的程序开发中。这里主要举两个例子来简要阐述结构化存储的应用。
1、创建结构化存储文件
这里介绍如何一个具有两个层次的结构化存储文件,一个Root-IStorage,一个Sub-IStorage,在Sub-Istorage下一个IStream。
Uses Activex, axctrls,comobj;
Procedure CreateSTGFile;
Var
RootSTG,SubSTG :IStorage;
IST :IStream
OST :TOLESTream;
temp :Pchar;
Begin
Try
//建立根存储接口 (Root-IStorage)
olecheck(
stgcreatedocFile('demo.stg',
stgm_create or stgm_readwrite or stgm_share_exclusive,
0,RootSTG));
//创建子存储接口
olecheck(
RootSTG.CreateStorage('substorage',
stgm_create or stgm_write or stgm_share_exclusive,
0,0,subSTG));
//创建IStream
olecheck(substg.createstream('descript',
stgm_create or stgm_write or stgm_share_exclusive,
0,0,IST));
//创建OLEStream
OST:=TOLEStream.create(IST);
Temp:='结构化存储文件演示';
OST.write(temp^,length(string(temp))); //写入数据
OST.Free;
except
on EoleSysError do showmessage('File Create Error!');
end;
End;
2、读取结构化存储文件
这里介绍如何读取上面建立的文件
Procedure ReadSTGFile;
Var
RootSTG,SubSTG :IStorage;
IST :IStream
OST :TOLESTream;
temp :array[1..1024] of char;
Begin
Try
//判断是否为结构化存储文件
if StgIsStorageFile('Demo.stg')<>S_OK then exit;
//打开文件,获取Root IStorage接口
olecheck(stgopenstorage('Demo.stg',nil,
stgm_readwrite or stgm_share_exclusive,
nil,0,RootSTG));
//获取sub IStorage接口
olecheck(rootSTG..openStorage('substorage',nil,
stgm_readwrite or stgm_share_exclusive,
nil,0,substg));
//获取IStream接口
olecheck(substg.openstream('descript',nil,
stgm_readwrite or stgm_share_exclusive,
0, IST));
//创建OLEStream
OST:=TOLEStream.create(IST);
Fillchar(temp,sizeof(temp),0);
OST.read(temp,sizeof(temp)); //读取数据
Showmessage(strpas(@temp));
OST.Free;
Except
on EoleSysError do showmessage('File Open&read Error!');
End;
以上只是最简单的两个应用列子,用户可以根据自己的实际需要加以拓展应用,通过TOLEStream类可以轻松地把压缩和加密技术运用到结构化存储文件中去。