istorage 封装 结构化存储_复杂的结构化存取(一)

本文介绍了Windows系统通过COM接口提供的复杂结构化存储,即复合文档,支持类似Windows目录结构的文件组织。重点讨论了IStorage、IStream和IEnumStatStg接口,以及如何使用这些接口进行存取操作。复合文件常用于OLE,允许创建自定义文件格式,并支持多线程访问。
摘要由CSDN通过智能技术生成

之所以说复杂, 就是区别与以前谈到的 结构化文件存取; 这种复杂的结构化文件也有叫做"复合文档".

有些文档不是结构化的, 譬如记事本文件; 结构化的档可以分为以下几类:

标准结构化文档、自定义结构化文档(譬如 bmp 文件)和复合文档.

这里要谈到的结构化储存(复合文档)是由 Windows 系统通过 COM 提供的, 它能完成像 Windows 目录结构一样复杂的文件结构的存取; 提示一下 Windows 的目录结构: 一个目录下可以包含子目录和文件, 然后层层嵌套...

有时我们要存储的文件也可能会层层分支, 具体的文件内容也可能五花八门, 譬如分支当中的某个文件是张图片、是一个字符串列表、是一个记录(或叫结构)等等, 存储这样的文件内容恐怕用数据库也是无能为力的.

这种复合文件支持多线程, 不同的进程中的不同线程可以同时访问一个复合文件的不同部分.

复合文件最典型的实例就是 OLE(譬如在 Word 中可以嵌入电子表格); 这也或许是这种复合文件的来由.

或许有了这个东西, 出品属于自己的文件格式就成了轻而易举的事情了.

存取和访问复合文档主要使用定义在 Activex 单元的三个 COM 接口:

IStorage (类似于 Windows 的目录, 也就是文件夹);

IStream (类似于目录中的文件, 不过在这里都是"流", 每个流至少要占用 512 字节);

IEnumStatStg (用于列举 IStorage 的层次结构)

"接口" 又是一个复杂的概念, 暂时把它认作是一组函数的集合吧.

下面罗列出了所有相关的函数(现在还没有全部掌握, 学习过程中再慢慢注释):

IStorage 中的函数:

//创建一个子 IStorage 接口

function CreateStorage(

pwcsName: POleStr; {指定子 IStorage 接口的名称}

grfMode: Longint; {指定访问模式}

dwStgFmt: Longint; {保留, 须是 0}

reserved2: Longint; {保留, 须是 0}

out stg: IStorage {返回子 IStorage 接口}

): HResult; stdcall;

//打开当前 IStorage 的子 IStorage

function OpenStorage(

pwcsName: POleStr; {指定子 IStorage 接口的名称}

const stgPriority: IStorage; {已存在的 IStorage 接口, 一般为 nil}

grfMode: Longint; {指定访问模式}

snbExclude: TSNB; {是个指针, 一般为 nil; 好像是指定要排除的元素}

reserved: Longint; {保留, 须是 0}

out stg: IStorage {返回打开的子 IStorage 接口}

): HResult; stdcall;

//创建一个子 IStream 接口

function CreateStream(

pwcsName: POleStr; {指定子 IStream 接口的名称}

grfMode: Longint; {指定访问模式}

reserved1: Longint; {保留, 须是 0}

reserved2: Longint; {保留, 须是 0}

out stm: IStream {返回子 IStream 接口}

): HResult; stdcall;

//打开当前 IStorage 的子 IStream

function OpenStream(

pwcsName: POleStr; {指定子 IStream 接口的名称}

reserved1: Pointer; {保留, 须为 nil}

grfMode: Longint; {指定访问模式}

reserved2: Longint; {保留, 须是 0}

out stm: IStream {返回子 IStream 接口}

): HResult; stdcall;

//复制 IStorage, 该函数可以实现“整理文件,释放碎片空间”的功能

function CopyTo(

ciidExclude: Longint; {要排除的元素数, 可以是 0}

rgiidExclude: PIID; {好像是以 PIID 的方式指定要排除的元素, 可以是 nil}

snbExclude: TSNB; {指定要被排除的元素, 一般为 nil}

const stgDest: IStorage {目标 IStorage}

): HResult; stdcall;

//复制或移动 "子 IStorage" 或 "子 IStream"

function MoveElementTo(

pwcsName: POleStr; {要复制或移动的 IStorage 或 IStream 的名称}

const stgDest: IStorage; {目标 IStorage 的名称}

pwcsNewName: POleStr; {给复制或移动后的 IStorage 或 IStream 指定新的名称}

grfFlags: Longint {指定是复制还是移动, 可选值: STGMOVE_MOVE、STGMOVE_COPY}

): HResult; stdcall;

//提交更改, 确保更改后的流能反映在父级存储中

function Commit(

grfCommitFlags: Longint {提交方式, 四个可选值见下面}

): HResult; stdcall;

//grfCommitFlags 可选值:

STGC_DEFAULT = 0;

STGC_OVERWRITE = 1;

STGC_ONLYIFCURRENT = 2;

STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4;

//放弃自从上次 Commit 调用以来对事务处理流所做的所有更改

function Revert: HResult; stdcall;

//获取当前 IStorage 的 IEnumStatStg 接口变量; IEnumStatStg 列举了 IStorage 的层次结构

function EnumElements(

reserved1: Longint; {保留, 须为 0}

reserved2: Pointer; {保留, 须为 nil}

reserved3: Longint; {保留, 须为 0}

out enm: IEnumStatStg {返回 IEnumStatStg 接口变量}

): HResult; stdcall;

//删除 "子 IStorage" 或 "子 IStream"

function DestroyElement(

pwcsName: POleStr {指定名称}

): HResult; stdcall;

//重命名 "子 IStorage" 或 "子 IStream"

function RenameElement(

pwcsOldName: POleStr; {原名}

pwcsNewName: POleStr {新名}

): HResult; stdcall;

//设置元素的时间信息

function SetElementTimes(

pwcsName: POleStr; {元素名}

const ctime: TFileTime; {创建时间}

const atime: TFileTime; {访问时间}

const mtime: TFileTime {修改时间}

): HResult; stdcall;

//在当前存储中建立一个特殊的流对象,用来保存 CLSID

function SetClass(

const clsid: TCLSID {}

): HResult; stdcall;

//设置状态位

function SetStateBits(

grfStateBits: Longint; {}

grfMask: Longint {}

): HResult; stdcall;

//返回一个 TStatStg 结构, 此结构包含该 IStorage 详细信息, 结构框架附下

function Stat(

out statstg: TStatStg; {TStatStg 结构变量}

grfStatFlag: Longint {选项, 此值可决定是否返回成员值, 见下}

): HResult; stdcall;

//TStatStg 结构:

tagSTATSTG = record

pwcsName: POleStr;

dwType: Longint;

cbSize: Largeint;

mtime: TFileTime;

ctime: TFileTime;

atime: TFileTime;

grfMode: Longint;

grfLocksSupported: Longint;

clsid: TCLSID;

grfStateBits: Longint;

reserved: Longint;

end;

TStatStg = tagSTATSTG;

//grfStatFlag 可选值:

STATFLAG_DEFAULT = 0;

STATFLAG_NONAME = 1;

IStream 中的函数:

//从 IStream 中读取数据

function Read(

pv: Pointer; {接受数据的变量的指针}

cb: Longint; {要读取的字节数}

pcbRead: PLongint {实际读出的字节数}

): HResult; stdcall;

//向 IStream 写入数据

function Write(

pv: Pointer; {要写入的数据的指针}

cb: Longint; {要写入的字节数}

pcbWritten: PLongint {实际写入的字节数}

): HResult; stdcall;

//移动指针

function Seek(

dlibMove: Largeint; {要移动的字节数}

dwOrigin: Longint; {指定移动的起点, 三种取值分别是: 开始、当前、结尾}

out libNewPosition: Largeint {返回新位置指针}

): HResult; stdcall;

//dwOrigin 可选值:

STREAM_SEEK_SET = 0; {开始}

STREAM_SEEK_CUR = 1; {当前}

STREAM_SEEK_END = 2; {结尾}

//更改流对象的大小

function SetSize(

libNewSize: Largeint {指定新的大小, 以字节为单位}

): HResult; stdcall;

//复制部分数据到另一个 IStream

function CopyTo(

stm: IStream; {目标 IStream}

cb: Largeint; {要复制的字节数}

out cbRead: Largeint; {从源中实际读出的字节数}

out cbWritten: Largeint {向目标实际写入的字节数}

): HResult; stdcall;

//提交更改, 确保更改后的流能反映在父级存储中

function Commit(

grfCommitFlags: Longint {提交方式, 四个可选值见下面}

): HResult; stdcall;

//grfCommitFlags 可选值:

STGC_DEFAULT = 0;

STGC_OVERWRITE = 1;

STGC_ONLYIFCURRENT = 2;

STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4;

//放弃自从上次 Commit 调用以来对事务处理流所做的所有更改

function Revert: HResult; stdcall;

//限制对流中指定字节范围的访问

function LockRegion(

libOffset: Largeint; {起始字节(从头算)}

cb: Largeint; {范围长度, 以字节为单位}

dwLockType: Longint {限制类型, 可选值附下面}

): HResult; stdcall;

//dwLockType 可选值:

LOCK_WRITE = 1;

LOCK_EXCLUSIVE = 2;

LOCK_ONLYONCE = 4;

//移除用 LockRegion 设定的字节范围的访问限制, 参数同 LockRegion

function UnlockRegion(

libOffset: Largeint; {}

cb: Largeint; {}

dwLockType: Longint {}

): HResult; stdcall;

//返回一个 TStatStg 结构, 此结构包含该 IStream 详细信息, 结构框架附下

function Stat(

out statstg: TStatStg; {TStatStg 结构变量}

grfStatFlag: Longint {选项, 此值可决定是否返回成员值, 见下}

): HResult; stdcall;

//TStatStg 结构:

tagSTATSTG = record

pwcsName: POleStr;

dwType: Longint;

cbSize: Largeint;

mtime: TFileTime;

ctime: TFileTime;

atime: TFileTime;

grfMode: Longint;

grfLocksSupported: Longint;

clsid: TCLSID;

grfStateBits: Longint;

reserved: Longint;

end;

TStatStg = tagSTATSTG;

//grfStatFlag 可选值:

STATFLAG_DEFAULT = 0;

STATFLAG_NONAME = 1;

//再制一个与指定 IStream 相同的副本

function Clone(

out stm: IStream {指定 IStream}

): HResult; stdcall;

IEnumStatStg 中的函数:

//检索枚举序列中指定数目的项

function Next(

celt: Longint; {}

out elt; {}

pceltFetched: PLongint {}

): HResult; stdcall;

//跳过枚举序列中指定数目的项

function Skip(

celt: Longint {枚举中要跳过的元素数目}

): HResult; stdcall;

//将枚举序列重置到开始处

function Reset: HResult; stdcall;

//再制一个相同的 IEnumStatStg

function Clone(

out enm: IEnumStatStg {}

): HResult; stdcall;

相关的函数还有:

//创建一个复合文档, 并通过参数返回 IStorage 接口

function StgCreateDocfile(

pwcsName: POleStr; {指定文件名}

grfMode: Longint; {指定访问模式}

reserved: Longint; {保留, 须是 0}

out stgOpen: IStorage {返回 IStorage 接口}

): HResult; stdcall;

//打开一个复合文档, 并通过参数返回 IStorage 接口

function StgOpenStorage(

pwcsName: POleStr; {指定文件名}

stgPriority: IStorage; {已存在的 IStorage 接口, 一般为 nil}

grfMode: Longint; {指定访问模式}

snbExclude: TSNB; {是一个 POleStr(双字节字符串)类型的指针, 一般为 nil}

reserved: Longint; {保留, 须是 0}

out stgOpen: IStorage {返回 IStorage 接口}

): HResult; stdcall;

//判断指定文件是否是按照结构化方式存储的

function StgIsStorageFile(

pwcsName: POleStr {文件名}

): HResult; stdcall;

//

function StgCreateDocfileOnILockBytes(

lkbyt: ILockBytes; {}

grfMode: Longint; {}

reserved: Longint; {}

out stgOpen: IStorage {}

): HResult; stdcall;

//

function StgOpenStorageOnILockBytes(

lkbyt: ILockBytes; {}

stgPriority: IStorage; {}

grfMode: Longint; {}

snbExclude: TSNB; {}

reserved: Longint; {}

out stgOpen: IStorage {}

): HResult; stdcall;

//

function StgIsStorageILockBytes(

lkbyt: ILockBytes {}

): HResult; stdcall;

//

function StgSetTimes(

pszName: POleStr; {}

const ctime: TFileTime; {}

const atime: TFileTime; {}

const mtime: TFileTime {}

): HResult; stdcall;

//

function StgOpenAsyncDocfileOnIFillLockBytes(

flb: IFillLockBytes; {}

grfMode, asyncFlags: Longint; {}

var stgOpen: IStorage {}

): HResult; stdcall;

//

function StgGetIFillLockBytesOnILockBytes(

ilb: ILockBytes; {}

var flb: IFillLockBytes {}

): HResult; stdcall;

//

function StgGetIFillLockBytesOnFile(

pwcsName: POleStr; {}

var flb: IFillLockBytes {}

): HResult; stdcall;

//

function StgOpenLayoutDocfile(

pwcsDfName: POleStr; {}

grfMode, reserved: Longint; {}

var stgOpen: IStorage {}

): HResult; stdcall;

//读出 WriteClassStg 写入的 CLSID, 相当于简化调用 IStorage.Stat

function ReadClassStg(

stg: IStorage; {}

out clsid: TCLSID {}

): HResult; stdcall;

//写 CLSID 到存储中, 同IStorage.SetClass

function WriteClassStg(

stg: IStorage; {}

const clsid: TIID {}

): HResult; stdcall;

//读出 WriteClassStm 写入的 CLSID

function ReadClassStm(

stm: IStream; {}

out clsid: TCLSID {}

): HResult; stdcall;

//写 CLSID 到流的开始位置

function WriteClassStm(

stm: IStream; {}

const clsid: TIID {}

): HResult; stdcall;

//写入用户指定的剪贴板格式和名称到存储中

function WriteFmtUserTypeStg(

stg: IStorage; {}

cf: TClipFormat; {}

pszUserType: POleStr {}

): HResult; stdcall;

//读出 WriteFmtUserTypeStg 写入的信息

function ReadFmtUserTypeStg(

stg: IStorage; {}

out cf: TClipFormat; {}

out pszUserType: POleStr {}

): HResult; stdcall;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值