ArcEngine 序列化和反序列化
相关网址:http://www.cnblogs.com/wall/archive/2009/02/26/1398447.html
http://www.gisall.com/html/77/27977-1183.html
http://blog.csdn.net/yanleigis/article/details/4770267
ArcEngine 中有很多对象是可以序列化,凡是实现了IPersistStream接口的对象都可序列化,序列化之后的好处呢有很多,比如:你可以将Ilayer,IfeatureLayer,Irasterlayer,ifeatureSender....等等序列化之后存为文件保存起来,或者是将序列化之后的对象转为字节数组存到数据库中保存,上述对象一般都是存有图层的信息,存起来之后有利于我们调用各种显示效果。ArcEngine 中对象属于COM对象,当我们在做多线程程序处理GIS数据的时候这些COM对象是不能轻易的在线程间传递的,此时我们就能利用AE提供的序列化功能将这些COM对象序列化为自己数组或是文件来达到线程间数据共享的目的。
一、AE对象序列化后转成字节数组和从字节数组反序列化为AE对象
1、AE对象序列化后转成字节数组
/// <summary>
/// 将传入的AE对象序列化成byte数组
/// </summary>
/// <param name="objData">要序列化的数据</param>
/// <param name="type">序列化的类别,0:rasterlayer,1:featurelayer</param>
private byte[] CreateByteFromObjData(object objData,int type)
{
//Engine中的BlobStream对象
IMemoryBlobStream pBlobStream = new MemoryBlobStream();
//将传入的对象转为IPersistStream
IPersistStream pPerStreamout = (IPersistStream)objData;
//存入BlobStream
pPerStreamout.Save(pBlobStream, 0);
//转换为Variant类型
IMemoryBlobStreamVariant pVar = (IMemoryBlobStreamVariant)pBlobStream;
object pobj = new object();
//转入Object对象
pVar.ExportToVariant(out pobj);
//强制转换为Byte数组,并返回
byte[] tempRaster = pobj as byte[];
return tempRaster ;
}
2、从字节数组反序列化为AE对象
/// <summary>
/// 将byte数组反序列化为AE对象
/// </summary>
///<param name="type">反序列化类型,0:irasterlayer,1:Ifeaturelayer</param>
private IPersistStream GetRasterLayerFromByte(byte[] tempByte )
{
IMemoryBlobStream pBlobStream = new MemoryBlobStreamClass();
IMemoryBlobStreamVariant pVar = (IMemoryBlobStreamVariant)pBlobStream;
IPersistStream pPerStreamout = null;
object pobj = tempByte as object;
//从Byte数据读取数据
pVar.ImportFromVariant(pobj);
//根要转换的类型创建不同的IPersistStream 对象
pPerStreamout = new RasterLayerClass();
//载入数据,并强制转换为ILayer类型
pPerStreamout.Load(pBlobStream);
return pPerStreamout;
}
返回的是一个IPersistStream ,根据你在代码中创建的IPersistStream在接口查询到要使用的接口
二、AE对象序列化后存为文件和从文件反序列化为AE对象
/// <summary>
/// 序列化AE对象
/// </summary>
/// <param name="gisObj"></param>
private void SerializeArcGisObject(object gisObj)
{
//转换成IPersistStream对象
IPersistStream ps = gisObj as IPersistStream;
//如果是继承了IPersistStream接口,则序列化
if (ps != null)
{
定义一种流对象;这里使用了MemoryBlobStreamClass
MemoryBlobStreamClass mbsc = new MemoryBlobStreamClass();
//把对象保存到流中
ps.Save(mbsc, 0);
//保存成文件
mbsc.SaveToFile(path);
}
}
private IRasterLayer DeserializeArcGisObject(string filename, IRasterLayer rasterLayer)
{
//定义一种流对象;这里使用了MemoryBlobStreamClass
//使用流读取文件
IBlobStream mbsc = new MemoryBlobStreamClass();
//使用流读取文件
mbsc.LoadFromFile(path);
IObjectStream pObjectStream=new ObjectStreamClass();
pObjectStream.Stream = mbsc as IStream;
ESRI.ArcGIS.esriSystem.IPersistStream ips = rasterLayer as IPersistStream;
ips.Load(pObjectStream as IStream);
return rasterLayer;
}
三、序列化为XML(从网上刮来的,还未用过)
1.序列化和反序列化Geometry对象
public void TestSrializePoint()
{
IPoint pPoint = new PointClass();
pPoint.X = 10;
pPoint.Y = 10;
IXMLStream pStream = new XMLStreamClass();
IXMLWriter pWriter = new XMLWriterClass();
pWriter.WriteTo((IStream) pStream);
IXMLSerializer pSerializer = new XMLSerializerClass();
pSerializer.WriteObject(pWriter, null, null, "", "", pPoint);
pStream.SaveToFile("C:\\Point.XML");
IXMLStream pStream2 = new XMLStreamClass();
pStream.LoadFromFile("C:\\Point.XML");
IXMLReader pReader = new XMLReaderClass();
pReader.ReadFrom( (IStream)pStream);
IXMLSerializer pSerializer2 = new XMLSerializerClass();
IPoint point = (IPoint)pSerializer2.ReadObject(pReader, null, null);
MessageBox.Show(point.SpatialReference.Name);
}
2.序列化和反序列化IRecordset对象
/// <summary>
/// 将一个FeatureClass中指定范围的Recordset序列化成XML文档
/// </summary>
/// <param name="featureClass"></param>
public void WriteXMLToDisk(IFeatureClass featureClass)
{
string ss= "http://www.esri.com/schemas/ArcGIS/9.0"; ;
IPropertySet pPropset = new PropertySetClass();
pPropset.SetProperty( "Namespaceuri", "http://schemas.esri.com/ArcGis/Server/");
IPropertySet pCpropset = new PropertySetClass();
pCpropset.SetProperty("http://schemas.esri.com/ArcGis/Server/", "xmlns");
pPropset.SetProperty ("Namespaceprefixes", pCpropset);
//IFeatureClass featureClass=featureLayer.FeatureClass;
IRecordSetInit recordSetInit=new RecordSetClass();
IRecordSet recordSet;
IQueryFilter queryFilter = new QueryFilterClass();
//queryFilter.SubFields = "Shape";
queryFilter.WhereClause = "FID=22";
recordSetInit.SetSourceTable((ITable)featureClass, queryFilter);
recordSet = (IRecordSet)recordSetInit;
IXMLStream xmlStream = new XMLStreamClass();
IXMLWriter xmlWriter = new XMLWriterClass();
xmlWriter.WriteTo((IStream)xmlStream);
IXMLSerializer XmlSerializer = new XMLSerializerClass();
try
{
XmlSerializer.WriteObject(xmlWriter, pPropset, null, "Record", ss, recordSet);
xmlStream.SaveToFile("C:\\Record.xml");
}
catch (System.Runtime.InteropServices.COMException ex)
{
throw new ArgumentException(ex.Message);
}
finally
{
GC.Collect();
}
}
/// <summary>
/// 将序列化的IRecodset文本反序列化成一个IRecordset对象
/// </summary>
/// <param name="strXmlPath"></param>
/// <returns></returns>
public IRecordSet ReadXmlFromDisk(string strXmlPath)
{
IXMLStream XmlStream = new XMLStreamClass();
XmlStream.LoadFromFile(strXmlPath);
IXMLReader XmlReader = new XMLReaderClass();
XmlReader.ReadFrom((IStream)XmlStream);
IXMLSerializer XmlSerializer = new XMLSerializerClass();
IRecordSet recordSet = (IRecordSet)XmlSerializer.ReadObject(XmlReader, null, null);
return recordSet;
}
以前做惟一值渲染时,为满足特定应用,曾想将每个要素对应的Symbol存入该要素字段中,当时考虑到Field Type中有一个Blob类型,美美地想如果将Symol转化成了Blob,岂不大功告成?在DevelopHelp中翻江倒海,欣喜地发现了IPersistStream这个接口,顺藤摸瓜找到了IMemoryBlobStream, 立马打开VS,敲码如下:
public void SaveSymbolToField(IFeature feature, string field, ISimpleLineSymbol symbol)
{
IPersistStream persistStream = symbol as IPersistStream;
IMemoryBlobStream memoryBlobStream = new MemoryBlobStreamClass();
persistStream.Save(memoryBlobStream, 0);
int index = feature.Fields.FindField(field);
feature.set_Value(index, memoryBlobStream);
feature.Store();
}
public ISimpleLineSymbol ReadSymbolFromField(IFeature feature, string field)
{
int index = feature.Fields.FindField(field);
IMemoryBlobStream memoryBlobStream = feature.get_Value(index) as IMemoryBlobStream;
IPersistStream persistStream = new SimpleLineSymbolClass();
persistStream.Load(memoryBlobStream);
return persistStream as ISimpleLineSymbol;
}
保存符号的函数没有问题,但读取符号的函数在persistStream.Load(memoryBlobStream)这一行熄了火,百度谷歌必应劳而无功后,愤怒的写下如下代码,本以为不可能有问题:
IPersistStream persistStream = symbol as IPersistStream;
IMemoryBlobStream memoryBlobStream = new MemoryBlobStreamClass();
persistStream.Save(memoryBlobStream, 0);
IPersistStream persistStream2 = new SimpleLineSymbolClass();
persistStream2.Load(memoryBlobStream);
但还是在Load处卡壳,让人怀疑IPersistStream的能力,不过如果采用以下狗血的方式,则能通过
IPersistStream persistStream = symbol as IPersistStream;
IMemoryBlobStream memoryBlobStream = new MemoryBlobStreamClass();
persistStream.Save(memoryBlobStream, 0);
memoryBlobStream.SaveToFile("D:\\Symbol.blb");
memoryBlobStream.LoadFromFile("D:\\Symbol.blb");
IPersistStream persistStream2 = new SimpleLineSymbolClass();
persistStream2.Load(memoryBlobStream);
什么原因至今未弄明白,想在字段中保存的Symbol的想法也被文件式保存取代,以上困惑,还请高手指教。
前面是旧事重提了,今天又遇到类似的问题,所不同的是想在要素的字段中保存一个Element,真是作孽。由于时间久远,又在老路上浪费不少生命,无奈之下,再度求助DevelopHelp,发现还有一个IMemoryBlobStreamVariant接口未用,并且惊喜的发现这个接口有一个将MemoryBlob输出为Byte[]数组的方法,想到Byte[]数组可以与String相互转换,计上心来。Blob类型没必要用了,直接建一个普通的String类型字段就可以拿来保存Element了,当然这个字段的长度一定要设的足够大,最好用String字段长度的最大值2147483647,因为天知道一个Element对象转换得来的字符串有多长,还是小心谨慎的好。这样一试,竟然圆满了,喜出望外啊,第一时间跑到坛子上来分享。
public void SaveElementToField(IFeature feature, string field, IMarkerElement element)
{
IMemoryBlobStream pMemoryBlobStream = new MemoryBlobStreamClass();
IPersistStream pPersistStream = element as IPersistStream;
pPersistStream.Save(pMemoryBlobStream, 0);
IMemoryBlobStreamVariant mbv = pMemoryBlobStream as IMemoryBlobStreamVariant;
object obj;
mbv.ExportToVariant(out obj);
byte[] bobj = (byte[])obj;
string str = Convert.ToBase64String(bobj);
int index = feature.Fields.FindField(field);
feature.set_Value(index, str);
feature.Store();
}
public IMarkerElement ReadElementFromField(IFeature feature, string field)
{
int index = feature.Fields.FindField(field);
string str = feature.get_Value(index).ToString();
byte[] bobj = Convert.FromBase64String(str);
IMemoryBlobStream pMemoryBlobStream = new MemoryBlobStreamClass();
IMemoryBlobStreamVariant mbv = pMemoryBlobStream as IMemoryBlobStreamVariant;
mbv.ImportFromVariant((object)bobj);
IPersistStream pPersistStream = new MarkerElementClass();
pPersistStream.Load(pMemoryBlobStream);
return pPersistStream as IMarkerElement;
}
/// <summary> /// 序列化(将对象序列化成xml文件) /// </summary> /// <param name="xmlfile">序列化文件路径</param> /// <param name="obj">序列化对象</param> /// <returns></returns> public static bool xmlSerializer(string xmlfile,object obj) { try { //判断是否支持IPersistStream接口,只有支持该接口的对象才能进行序列化 if (obj is ESRI.ArcGIS.esriSystem.IPersistStream) { ESRI.ArcGIS.esriSystem.IPersistStream pStream = obj as ESRI.ArcGIS.esriSystem.IPersistStream; ESRI.ArcGIS.esriSystem.IXMLStream xmlStream = new ESRI.ArcGIS.esriSystem.XMLStreamClass(); pStream.Save(xmlStream as ESRI.ArcGIS.esriSystem.IStream, 0); xmlStream.SaveToFile(xmlfile); return true; } return false; } catch (System.Exception e) { return false; } } -------------------------------------------------------------------------------- /// <summary> /// 反序列化(将xml反序列化成指定的对象) /// </summary> /// <param name="xmlPathFile">序列化文件</param> /// <param name="obj">序列化对象</param> /// <returns></returns> public static bool XmlDeSerializer(string xmlPathFile,ref object obj) { try { //判断文件是否存在 if (System.IO.File.Exists(xmlPathFile) && System.IO.Path.GetExtension(xmlPathFile) == ".xml") { ESRI.ArcGIS.esriSystem.IPersistStream pStream = obj as ESRI.ArcGIS.esriSystem.IPersistStream; ESRI.ArcGIS.esriSystem.IXMLStream xmlStream = new ESRI.ArcGIS.esriSystem.XMLStreamClass(); xmlStream.LoadFromFile(xmlPathFile); pStream.Load(xmlStream as ESRI.ArcGIS.esriSystem.IStream); return true; } return false; } catch(Exception ex) { return false; } }
浙公网安备 33010602011771号