COM結構化存儲

COM結構化存儲（也稱「OLE結構化存儲」）是微軟在Windows作業系統上開發的一種技術，以在一個文件記憶體儲層次化的數據。嚴格講，術語「structured storage」是指COM的一套接口。並提供了有限形式的原子事務數據訪問。

結構化存儲廣泛用於Microsoft Office應用程式。但從Office 2007開始默認使用基於XML的Office Open XML。SQL Server也使用結構化存儲。

## 概述

結構化存儲是為了解決在一個文件中存放多個數據對象的本質性困難。當修改一個對象從而改變其尺寸時，如果這些對象在文件內是順序存放的，則被修改對象的尺寸擴大時所有在其後的對象都需要向後移動以騰出空間，被修改對象縮小尺寸時所有在其後的對象都需要向前移動。這樣的困難有很多種辦法應對，但應用程式開發者並不希望處理這樣低層次的二進位文件格式問題。

結構化存儲把文件系統的概念引入到文件內部。在文件內部構造一個樹狀層次結構。由存儲對象和流對象構成。根節點為根存儲，根存儲下面可以有子存儲或流對象。子存儲下面可以再有子存儲或流對象。存儲對象本身不包含資訊，它是子存儲和流對象的容器。流對象是葉子節點，是數據的載體。

## COM接口

### 簡介

結構化存儲提供了一種抽象，稱為「流」（stream），用COM接口`IStream`表示。一個流在概念上類似一個文件，使用`IStream`接口的方法來讀寫。流可以存在於記憶體中、文件中，或其它流中。另外一個重要抽象是「storage」，表示為COM接口`IStorage`。一個storage在概念上類似於文件系統的目錄。Storage可以包含流或其他storages。

一個應用程式如果要把幾個數據對象保存到一個文件中，一種辦法是打開一個`IStorage`以表示文件，然後把 每個對象存入單獨的`IStream`（這可通過標準COM接口`IPersistStream`）。

結構化存儲的事務機制，針對寫模式而不是讀模式。創建、打開存儲和流時可以指定事務模式。只有Commit後，所有的變化才提交到上級。revert可以恢復到上次commit以來的狀態。事務的實現是在記憶體中或臨時文件中保存文件拷貝的方式。事務可以嵌套。

增量訪問，可以減少保存文件的操作時間。對於文件碎片，調用根存儲CopyTo解決。

### IStream接口

```
  class IStream::public IUnknown 
```

方法：

```
   Read
   Write
   Seek
   CopyTo
   Commit 把所有变化提交到包容该流对象的存储对象。
   Revert   rollback取消上次提交以来的所有操作。针对事务模式的流
```

### IStorage接口

```
   class IStorage：public IUnknown  
   CreateStream 
   OpenStream 操作子流对象，返回IStream接口指针
   CreateStorage 
   OpenStorage 操作子存储对象，返回IStorage接口指针
   EnumElements 枚举所有的子流对象和子存储对象。
   commit
   Revert。针对事务模式的存储。
   Stat 获取存储对象的CLSID标识符
   SetClass 为存储对象赋一个CLSID标识符，并可通过Stat函数获取此CLSID值。通过此CLSID值把存储对象与一段可执行代码联系起来，当客户程序希望执行与存储对象相联系的代码时，它利用CLSID值，并调用 CoCreateInstamce函数创建一个COM对象，再把存储对象交给COM对象，由它处理存储对象。 
```

### Windows API函數用於CLSID有關操作

- WriteClassStg和ReadClassStg函數封裝了 IStorage::SetClass和IStorage::Stat成員函數，可以完成存儲對象的CLSID的設置和獲取操作。存儲對象只是個容器，它本身不包含數據資訊，所以它的CLSID資訊被寫在其下面的一個子流對象中，其名字為「\x01CompObj」。
- WriteClassStm和ReadClassStm函數使用一致的格式在流對象的當前位置分別寫或者讀CLSID資訊。通常情況下，在流的起始處放置CLSID資訊。
- GetClassFile函數返回一個與給定文件相聯繫的CLSID。Windows利用CLSID把數據文件與應用程式聯繫起來。

## 複合二進位文檔

Microsoft實現的一種稱為複合二進位文檔（Compound File Binary Format，簡稱「複合文檔」）的COM結構化存儲，廣泛用於結構化存儲實現。使用類似於FAT的結構表示存儲與流。文件片（chunk）被稱為扇區（sector）按需分配給新的流或增加尺寸的流。如果流被刪除或收縮尺寸，不再需要的扇區可以重新被其他流使用。

使用複合二進位文檔的應用程式有：

- Word 文檔(.DOC, .DOT)
- Excel spreadsheets (.XLS, .XLT)
- PowerPoint presentations (.PPT, .POT)
- Publisher 文件(.PUB)
- Visio 文件(.VSD)
- Project 文件(.MPP)
- Microsoft PhotoDraw 文件(.MIX)
- Microsoft Outlook 文件(.MSG)
- Windows Installer 文件(.MSI, .MSP, .MST)
- Microsoft Picture It! / Microsoft Digital Image 文件(.MIX)
- Internet Explorer RSS Feeds Windows RSS Platform 文件(.feed-ms)
- Windows 7 StickyNotes (.SNT)
- Windows 7 jumplists 文件
- Thumbs.db
- Microsoft SQL 2000 Server DTS packages

### LockBytes對象

LockBytes對象是所有存儲介質的一種抽象。存儲介質描述稱為一般化的字節流，LockBytes對象負責從字節流中讀寫字節。複合文檔通過一個被稱為「LockBytes」的對象，把根存儲與底層的存儲介質聯繫起來，其他的子對象則通過根存儲與底層存儲介質進行數據通信，從而實現了整個結構化存儲體系結構。複合文檔通過LockBytes對象把根存儲對象與底層的文件操作隔離開來，在訪問存儲對象或者流對象時避開了文件句柄操作。

LockBytes對象實現了ILockBytes接口以提供基本的讀寫操作。COM庫提供了預設的基於文件句柄的LockBytes對象，以及基於記憶體的LockBytes對象。

例如，可按照如下步驟創建基於記憶體的複合文檔。

- GlobalAlloc獲得一個記憶體句柄
- CreateILockBytesOnHGlobal創建一個LockBytes對象。這步類似於GlobleLock
- StgCreateDocfileOnILockBytes創建一個基於指定的LockBytes對象的複合文檔

其他方法：

- 使用StgCreateDocfile創建一個基於磁碟文件的複合文檔。
- StgCreateDocfileOnLockBytes
- 使用StgOpenStorage打開一個基於磁碟文件的複合文檔
- 使用StgOpenStorageOnILockBytes打開一個基於記憶體的複合文檔
- GetHGlobalFromILockBytes
- CreateStreamOnHGlobal
- GetHGlobalFromStream
- StgIsStorageFile
- StgSetTimes

### 永久對象

概念上，永久對象與存儲對象和流對象沒有聯繫。永久對象可以把狀態資訊存儲下來，以後可以重建這樣的對象，且恢復到以前的狀態。可以很方便地使用COM的結構化存儲機制或別的機制（如磁碟文件，系統註冊表，目錄服務，資料庫服務等）來保存永久對象的狀態。

COM定義了四個常用的永久接口：IPersistStorage, IPersistStream, IPersistStreamInit 和IPersistFile。前三個接口使用的結構化存儲機制。後一個接口直接使用文件。接口都包含三個基本函數

- IsDirty：反映了自上次保存後是否被修改
- Load：從存儲介質中裝入永久對象的狀態數據
- Save：把永久對象的狀態數據保存到存儲介質中

## Native Structured Storage

During the beta testing phase of Windows 2000, it included a feature titled Native Structured Storage (NSS) for storage of Structured Storage documents (like the binary Microsoft Office formats and the `thumbs.db` file Windows Explorer uses to cache thumbnails) with each Stream that makes up a document stored in a separate NTFS data stream. It included utilities that automatically split up the streams in a regular Structured Storage document into NTFS data streams and vice versa. However, the feature was withdrawn after Beta 3 due to incompatibilities with other OS components, and any NSS files automatically converted to the single data stream format.

## 類似功能產品

- Microsoft .NET:
- GemBox.CompoundFile – .NET component for accessing structured storage files.
- OpenMCDF – Free .NET component for accessing OLE structured storage files, MPL licensed.
- GNOME Structured File Library – Can read Microsoft structured storage files.
- POLE.
- POLE v3 and up.
- POIFS – Java implementation of the OLE 2 Compound Document format, part of Apache POI.
- LAOLA Binary Structures

## 外部連結

- http://msdn.microsoft.com/en-us/library/aa380369%28VS.85%29.aspx
- Open Specifications: Compound File Binary File Format