ArcGIS Engine(AE)開発において、Layer、Element、Map、Legend、NorthArrowなどのオブジェクトをファイルやデータベースに保存したいケースは頻繁に発生します。FeatureLayerのFeatureはFeatureClassに直接保存できますが、GraphicsContainerに追加したElementについては標準的な保存機構が存在しないため、独自の永続化処理が必要になります。このような場合、オブジェクトをバイナリストリームやXML形式でシリアライズすることで、再利用可能な状態で保存・復元することが可能です。
シリアライズ対象となるオブジェクトは、IPersistStreamインターフェースを実装している必要があります。このインターフェースはWindows COM由来のもので、以下の4つのメソッドを通じてストリームとの入出力を行います:
| メソッド | 機能 |
|---|---|
IsDirty() | オブジェクトの状態が変更されたかを判定。保存が必要かどうかの判断材料 |
Load() | ストリームからデータを読み込み、オブジェクトを復元 |
Save() | オブジェクトの状態をストリームへ書き込み |
GetSizeMax() | 必要なバッファサイズを事前に取得 |
バイナリ形式でのシリアライズ/デシリアライズ
/// <summary>
/// オブジェクトをバイト配列に変換
/// </summary>
public static byte[] SerializeToBytes(object target)
{
if (!(target is IPersistStream streamable)) return null;
var blob = new MemoryBlobStreamClass();
var objStream = new ObjectStreamClass { Stream = blob };
streamable.Save(objStream, 0);
var size = (int)blob.Size;
var buffer = new byte[size];
((IMemoryBlobStreamVariant)blob).ExportToVariant(out var data);
return (byte[])data;
}
/// <summary>
/// バイト配列からオブジェクトを復元
/// </summary>
public static void DeserializeFromBytes(byte[] data, object target)
{
if (!(target is IPersistStream streamable) || data == null) return;
var blob = new MemoryBlobStreamClass();
blob.ImportFromMemory(ref data[0], (uint)data.Length);
var objStream = new ObjectStreamClass { Stream = blob };
streamable.Load(objStream);
}
/// <summary>
/// Esri BLOBフィールド値をバイト配列に変換
/// </summary>
public static byte[] ConvertEsriBlob(object fieldValue)
{
if (fieldValue == null || fieldValue == DBNull.Value) return null;
var blob = (IMemoryBlobStream2)fieldValue;
var size = (int)blob.Size;
var buffer = new byte[size];
((IMemoryBlobStreamVariant)blob).ExportToVariant(out var data);
return (byte[])data;
}
ファイルへの直接保存
/// <summary>
/// オブジェクトを指定パスのファイルに保存
/// </summary>
public static bool SaveObjectToFile(string filePath, object obj)
{
if (!(obj is IPersistStream persistStream)) return false;
var blobStream = new MemoryBlobStreamClass();
var objectStream = new ObjectStreamClass { Stream = blobStream };
persistStream.Save(objectStream, 0);
try
{
blobStream.SaveToFile(filePath);
return true;
}
catch
{
return false;
}
}
XML形式によるワークスペース接続情報の保存と復元
/// <summary>
/// ワークスペース接続情報をXML文字列に変換
/// </summary>
public static string SerializeWorkspace(IWorkspace workspace)
{
try
{
var xmlStream = new XMLStreamClass();
var writer = new XMLWriterClass();
writer.WriteTo(xmlStream as IStream);
var serializer = new XMLSerializerClass();
serializer.WriteObject(writer, null, null, "", "", workspace.ConnectionProperties);
return xmlStream.SaveToString();
}
catch
{
return string.Empty;
}
}
/// <summary>
/// XML文字列からワークスペースを復元
/// </summary>
public static IWorkspace DeserializeWorkspace(string xmlData, string password)
{
try
{
var xmlStream = new XMLStreamClass();
xmlStream.LoadFromString(xmlData);
var reader = new XMLReaderClass();
reader.ReadFrom(xmlStream as IStream);
var serializer = new XMLSerializerClass();
var propSet = serializer.ReadObject(reader, null, null) as IPropertySet;
if (propSet != null)
{
propSet.SetProperty("PASSWORD", password);
var factory = new SdeWorkspaceFactoryClass();
return factory.Open(propSet, 0);
}
}
catch
{
return null;
}
return null;
}