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）按需分配給新的流或增加尺寸的流。如果流被刪除或收縮尺寸，不再需要的扇區可以重新被其他流使用。
使用複合二進制文檔的應用程序有：- Microsoft Office 97–2003 文檔：
** 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.CompoundFiledate=20110702023525  – .NET component for accessing structured storage files.
**  OpenMCDFdate=20171120204141  – Free .NET component for accessing OLE structured storage files, MPL licensed.
*Linux:
**  GNOME Structured File Librarydate=20081015055623  – Can read Microsoft structured storage files.
**  POLE.
*跨平臺 C++用於 Window/MacOSX/Linux:
**  POLE v3 and update=20171205113110 .- Java:
**  POIFS – Java implementation of the OLE 2 Compound Document format, part of Apache POI.- Perl:
**  LAOLA Binary Structures

**參考文獻**

**外部鏈接**
 Open Specifications: Compound File Binary File Formatdate=20170503151931