亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

實例解析C++/CLI的串行化

2019-11-17 05:28:01
字體:
來源:轉載
供稿:網友

  串行化可使對象被轉換為某種外部的形式,比如以文件存儲的形式供程序使用,或通過程序間的通訊發送到另一個處理過程。轉換為外部形式的過程稱為"串行化",而逆過程稱為"反串行化"。

  簡介
  
  請看例1中的示例,其將多個對象類型的值寫入到一個新的磁盤文件中,關閉文件,接著再把這些值重新讀取到內存中。

  例1:

using namespace System;
using namespace System::IO;
using namespace System::Runtime::Serialization::Formatters::Binary;

int main()
{
 array<int>^ intArray = {10, 20, 30};
 array<float,2>^ floatArray = {
  {1.2F, 2.4F},
  {3.5F, 6.8F},
  {8.4F, 9.7F}
 };
 DateTime dt = DateTime::Now;
 Console::WriteLine("dt >{0}<", dt);

 /*1*/ BinaryFormatter^ formatter = gcnew BinaryFormatter;

 //將數據串行化到一個文件

 /*2*/ Stream^ file = File::Open("Sr01.ser", FileMode::Create);

 /*3a*/ formatter->Serialize(file, "Hello");
 /*3b*/ formatter->Serialize(file, intArray);
 /*3c*/ formatter->Serialize(file, floatArray);
 /*3d*/ formatter->Serialize(file, true);
 /*3e*/ formatter->Serialize(file, dt);
 /*3f*/ formatter->Serialize(file, 1000);
 /*3g*/ formatter->Serialize(file, L'X');
 /*3h*/ formatter->Serialize(file, 1.23456F);

 /*4*/ file->Close();

 //從文件中反串行化數據--即讀取數據

 /*5*/ file = File::Open("Sr01.ser", FileMode::Open);

 /*6a*/ String^ s = static_cast<String^>(formatter->Deserialize(file));
 Console::WriteLine("String >{0}<", s);

 /*6b*/ array<int>^ newIntArray =
 static_cast<array<int>^>(formatter->Deserialize(file));
 Console::WriteLine("newIntArray:");
 for (int i = 0; i < newIntArray->Length; ++i)
 {
  Console::Write(" {0}", newIntArray[i]);
 }
 Console::WriteLine();

 /*6c*/ array<float,2>^ newFloatArray =
 static_cast<array<float,2>^>(formatter->Deserialize(file));
 Console::WriteLine("newFloatArray:");
 for (int i = 0; i < 3; ++i)
 {
  for (int j = 0; j < 2; ++j)
  {
   Console::Write(" {0}", newFloatArray[i,j]);
  }
  Console::WriteLine();
 }

 /*6d*/ bool b = static_cast<bool>(formatter->Deserialize(file));
 Console::WriteLine("bool >{0}<", b);

 /*6e*/ DateTime newDT = static_cast<DateTime>(formatter->Deserialize(file));
 Console::WriteLine("newDT >{0}<", newDT);

 /*6f*/ int v = static_cast<int>(formatter->Deserialize(file));
 Console::WriteLine("int >{0}<", v);

 /*6g*/ wchar_t c = static_cast<wchar_t>(formatter->Deserialize(file));
 Console::WriteLine("wchar_t >{0}<", c);

 /*6h*/ float f = static_cast<float>(formatter->Deserialize(file));
 Console::WriteLine("float >{0}<", f);

 /*7*/ file->Close();
}
  在標記1中,我們定義了一個BinaryFormatter類型的變量,此種類型的任意對象都可以二進制的形式進行串行與反串行化。

  在標記2中,用指定的名稱創建了一個新的文件,后綴 .ser沒有非凡的意思,這是約定俗成的表示這是一個串行化數據文件。從標記3a至3h,表示一個對象被串行化至文件中。在字符串的情況下,每個字符都被寫入;在數組的情況下,所有元素都被寫入;在日期時間的情況下,類型中包含的所有數據及有關依靠項都被寫入;在為原始類型值的情況下,它們先被裝箱,然后對應的對象被寫入。上述動作中,串行化只需要接收一個Object^類型參數的對象即可。

  通過調用Deserialize函數,可取回串行化后的數據,如標記6a中所示;因為此函數返回一個Object^類型的值,所以需要把它轉換為相應的值。程序的輸出如插1所示:

  插1:例1中串行化、反串行化的輸出


String >Hello<
newIntArray
10 20 30
newFloatArray:
1.2 2.4
3.5 6.8
8.4 9.7
bool >True<
newDT >9/29/2005 3:25:44 PM<
int >1000<
wchar_t >X<
float >1.23456< 串行化包含引用的對象

  在前一個例子中,我們對相關類型進行了簡單的讀寫。那么,假如一個對象中包含了其他對象的句柄呢?試想有一個超過兩萬字的字典,存儲在一個能通過鍵值索引的集合中,而在標準模板庫中,就提供了一個這樣的集合--哈希表(Hashtable),如例2中所示:

  例2:

using namespace System;
using namespace System::IO;
using namespace System::Collections;
using namespace System::Runtime::Serialization::Formatters::Binary;

int main()
{
 /*1*/ Hashtable^ dictionary = gcnew Hashtable(21000);

 StreamReader^ inStream = File::OpenText("dictionary.txt"); //打開字典文件
 String^ str;

 while ((str = inStream->ReadLine()) != nullptr)
 {
  /*2*/ dictionary->Add(str, nullptr);
 }

 inStream->Close();
 /*3*/ Console::WriteLine("Dictionary contains {0} entries", dictionary->Count);

 BinaryFormatter^ formatter = gcnew BinaryFormatter();
 Stream^ file = File::Open("dictionary.ser", FileMode::Create);
 /*4*/ formatter->Serialize(file, dictionary);
 file->Close();
}
  在標記1中,我們先分配了一個初始化為21000個條目的哈希表(這樣做只是為了加快處理速度,在條目相加時不需要重新進行分配),接著從一個文本文件中,一次一行地讀入字,并將其添加到標記2的哈希表中。請注重,在定義中,哈希表的每個條目都由(鍵/值)對組成。但在我們的程序中,鍵也是值,所以在第二個參數中使用了nullPRt。

  哈希表中的鍵值必須是唯一的,而添加進來的任何類型的對象都必須重載System::對象名 GetHashCode函數--字符串也一樣。

  一旦文件中所有的字被讀取并添加到哈希表中,就可通過一個簡單的Serialize調用,把哈希表寫到磁盤上,如標記4所示。在例3中,我們讀入這個字典,并在其中查找用戶提供的字,插2是對應的輸出。

  例3:

using namespace System;
using namespace System::IO;
using namespace System::Collections;
using namespace System::Runtime::Serialization::Formatters::Binary;

int main()
{
 BinaryFormatter^ formatter = gcnew BinaryFormatter;

 Stream^ file = File::Open("dictionary.ser", FileMode::Open);
 /*1*/ Hashtable^ dictionary = static_cast<Hashtable^>(formatter->Deserialize(file));
 file->Close();

 /*2*/ Console::WriteLine("Dictionary contains {0} entries", dictionary->Count);

 String^ Word;
 while (true)
 {
  Console::Write("Enter a word: ");
  word = Console::ReadLine();
  if (word == nullptr)
  {
   break;
  }
  /*3*/ Console::WriteLine("{0}{1} found", word, (dictionary->Contains(word) ? "" : " not"));
 }
}
  插2:使用反串行化進行字典查找

Dictionary contains 20159 entries
Enter a word: house
house found
Enter a word: houses
houses not found
Enter a word: brick
brick found
Enter a word: manly
manly not found
  此處最重要的是,我們能在單個函數調用中,串行、反串行化任意大小、任意復雜性的對象。 處理多個句柄

  當我們傳遞一個對象的句柄給Serialize時,似乎會在底層對對象進行一個復制,那么,實際情況真的是這樣嗎?假設我們把包含有多個句柄的一個對象寫入到其他對象中,或者我們調用Serialize兩次,每次都給它同一個對象的句柄呢?我們真的想得到同一對象的多個副本嗎?在例4中演示了這個過程:

  例4:


using namespace System;
using namespace System::IO;
using namespace System::Runtime::Serialization::Formatters::Binary;

/*1*/ [Serializable]
ref class Employee { /* ... */};

int main()
{
 Employee^ emp1 = gcnew Employee();
 Employee^ emp2 = gcnew Employee();
 Employee^ emp3 = emp2;
 /*2a*/ Console::WriteLine("emp1 == emp2 is {0}", (emp1 == emp2));
 /*2b*/ Console::WriteLine("emp2 == emp3 is {0}", (emp2 == emp3));
 /*2c*/ Console::WriteLine("emp1 == emp3 is {0}", (emp1 == emp3));

 array<Object^>^ list = gcnew array<Object^>(2);
 list[0] = emp1;
 list[1] = list[0];
 /*2d*/ Console::WriteLine("list[0] == list[1] is {0}", (list[0] == list[1]));
 /*2e*/ Console::WriteLine("list[0] == emp1 is {0}", (list[0] == emp1));
 /*2f*/ Console::WriteLine("list[1] == emp1 is {0}", (list[1] == emp1));

 //將數據串行化到文件

 BinaryFormatter^ formatter = gcnew BinaryFormatter;
 Stream^ file = File::Open("Sr03.ser", FileMode::Create);

 /*3a*/ formatter->Serialize(file, emp1);
 /*3b*/ formatter->Serialize(file, emp2);
 /*3c*/ formatter->Serialize(file, emp3);
 /*3d*/ formatter->Serialize(file, list);

 file->Close();

 //從文件中反串行化數據--即讀取數據

 file = File::Open("Sr03.ser", FileMode::Open);

 /*4a*/ emp1 = static_cast<Employee^>(formatter->Deserialize(file));
 /*4b*/ emp2 = static_cast<Employee^>(formatter->Deserialize(file));
 /*4c*/ emp3 = static_cast<Employee^>(formatter->Deserialize(file));
 /*4d*/ list = static_cast<array<Object^>^>(formatter->Deserialize(file));

 file->Close();

 /*5a*/ Console::WriteLine("emp1 == emp2 is {0}", (emp1 == emp2));
 /*5b*/ Console::WriteLine("emp2 == emp3 is {0}", (emp2 == emp3));
 /*5c*/ Console::WriteLine("emp1 == emp3 is {0}", (emp1 == emp3));
 /*5d*/ Console::WriteLine("list[0] == list[1] is {0}", (list[0] == list[1]));
 /*5e*/ Console::WriteLine("list[0] == emp1 is {0}", (list[0] == emp1));
 /*5f*/ Console::WriteLine("list[1] == emp1 is {0}", (list[1] == emp1));
}
  在本例中,我們想對Employee類型(在標記1中的用戶自定義類型)的對象進行串行化,必須把Serializable屬性附加到這個類型上。假如我們試圖串行化一個沒有標明此屬性的類對象,將會拋出一個System::Runtime::Serialization::SerializationException類型的異常。串行化之前的程序輸出如插3所示:

  插3:串行化之前例4的輸出

emp1 == emp2 is False
emp2 == emp3 is True
emp1 == emp3 is False
list[0] == list[1] is True
list[0] == emp1 is True
list[1] == emp1 is True
  我們對四個目標進行了串行化,前兩個代表了不同的Employee對象,而第三個是對第二個的引用,第四個為包含兩個元素的數組,這兩個元素均引用第一個Employee對象。程序的輸出表明了它們之間的這些關系,反串行化之后的輸出見插4:

  插4:反串行化之后例4的輸出

emp1 == emp2 is False
emp2 == emp3 is False
emp1 == emp3 is False
list[0] == list[1] is True
list[0] == emp1 is False
list[1] == emp1 is False
  注重,現在第三個Employee句柄已不再是一個指向第二個Employee對象的句柄了,類似地,盡管list[0]與list[1]都引用同一個Empolyee對象,但對象已不是我們取回的第一個對象了。

  在此應看到,當多個對象逐個串行化之后,它們是相關聯的,而當反串行化之后,它們的關系并沒有因此而恢復,但是,對象內部的關系仍然被維持。
自定義的串行化

  默認情況下,當一個對象被串行化時,所有的非靜態實例字段都會被寫入,并在反串行化期間順序讀回;然而,對包含靜態字段的類,這可能會導致一個問題。

  在例5中使用了Point類,其不但包含了用于追蹤每個Point x與y坐標的實例變量,而且還會跟蹤在程序執行期間創建的Point數目。例如,在例5中,通過顯示構造函數調用,創建了4個Point,并將它們串行化到磁盤;當它們被反串行化時,又創建了4個新的Point,因此Point總數現在為8,插5中是程序的輸出:

  例5:

using namespace System;
using namespace System::IO;
using namespace System::Runtime::Serialization::Formatters::Binary;

int main()
{
 Console::WriteLine("PointCount: {0}", Point::PointCount);
 Point^ p1 = gcnew Point(15, 10);
 Point^ p2 = gcnew Point(-2, 12);
 array<Point^>^ p3 = {gcnew Point(18, -5), gcnew Point(25, 19)};
 Console::WriteLine("PointCount: {0}", Point::PointCount);
 
 BinaryFormatter^ formatter = gcnew BinaryFormatter;
 Stream^ file = File::Open("Point.ser", FileMode::Create);

 formatter->Serialize(file, p1);
 formatter->Serialize(file, p2);
 formatter->Serialize(file, p3);
 
 file->Close();

 file = File::Open("Point.ser", FileMode::Open);

 Point^ p4 = static_cast<Point^>(formatter->Deserialize(file));
 Console::WriteLine("PointCount: {0}", Point::PointCount);
 Point^ p5 = static_cast<Point^>(formatter->Deserialize(file));
 Console::WriteLine("PointCount: {0}", Point::PointCount);
 array<Point^>^ p6 = static_cast<array<Point^>^>(formatter->Deserialize(file));
 Console::WriteLine("PointCount: {0}", Point::PointCount);

 file->Close();

 Console::WriteLine("p1: {0}, p4: {1}", p1, p4);
 Console::WriteLine("p2: {0}, p5: {1}", p2, p5);
 Console::WriteLine("p3[0]: {0}, p6[0]: {1}", p3[0], p6[0]);
 Console::WriteLine("p3[1]: {0}, p6[1]: {1}", p3[1], p6[1]);
}
  插5:反串行化創建了4個新的Point

PointCount: 0
PointCount: 4
PointCount: 5
PointCount: 6
PointCount: 8
p1: (15,10), p4: (15,10)
p2: (-2,12), p5: (-2,12)
p3[0]: (18,-5), p6[0]: (18,-5)
p3[1]: (25,19), p6[1]: (25,19)
  當調用Point類的公有構造函數來構造一個新對象時,Point計數字段也會相應增長;而當我們反串行化一個或多個Point時,問題發生了,對Point的Deserialize調用實際上創建了一個新的Point對象,但它并沒有為這些對象調用任何的構造函數啊。另外要明確一點,即使新Point數被增量1 ,PointCount也不會自動增長。我們可重載由接口ISerializable(從System::Runtime::Serialization)實現的默認的串行與反串行動作;這個接口需要定義一個調用GetObjectData的函數,這個函數就可以答應我們重載串行化過程。

  GetObjectData函數的目的是,以串行化一個父類對象所需的數據,增加一個SerializationInfo對象,在此,名稱、值、類型信息都被提供給AddValue函數,并由對象作為第二個參數。名稱字符串可為任意,只要它在這種類型的串行化中唯一就行了。(假如使用了兩個相同的名稱,會拋出SerializationException異常。)

  假如要重載反串行化過程,必須定義另一個構造函數,注重這個構造為私有類型,因為它只會被反串行化機制所調用,沒有從外部訪問的必要。

  串行化的格式
  
  以上所有串行化的例子當中,我們使用了BinaryFormatter類型,其以某種能被高效地處理的壓縮格式來存儲數據;然而,其他格式也能做到這點,例如,可使用一個SOAP,SOAP(Simple Object access Protocol--簡單對象訪問協議)是一種用于在Web上交換結構化及類型信息的簡單的、基于xml的協議,該協議未包含任何應用程序或傳輸語義,所以它具有高度模塊化及擴展性的特點。當然,大家也能創建其他的自定義格式。


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区视频在线播放| 日韩高清欧美高清| 2019亚洲男人天堂| 久久国产精品久久久久久| 97在线视频免费| 欧美日韩另类在线| 午夜免费在线观看精品视频| 欧美性极品少妇精品网站| 成人夜晚看av| 日韩中文字幕在线免费观看| 亚洲欧美一区二区精品久久久| 国产亚洲精品va在线观看| 国产第一区电影| 一本色道久久88亚洲综合88| 欧美电影免费观看高清完整| 国产精品爽爽爽爽爽爽在线观看| 91在线色戒在线| 国外成人免费在线播放| 国模精品系列视频| 精品福利免费观看| 久久影视电视剧免费网站| 91久久久久久久久久| 亚洲福利视频网| 色偷偷av亚洲男人的天堂| 亚洲男人av在线| 欧美成人精品三级在线观看| 九九热最新视频//这里只有精品| 久久精品色欧美aⅴ一区二区| 日韩成人高清在线| 欧美性猛交xxxx富婆| 国产精品激情av电影在线观看| 精品久久久一区二区| 欧美网站在线观看| 一区二区三区日韩在线| 欧美一级大片在线免费观看| 91九色国产社区在线观看| 久久精品中文字幕| 久久国产精品久久久久久久久久| 日韩女在线观看| 亚洲综合在线播放| 不卡伊人av在线播放| 国产欧美精品在线| 亚洲综合精品伊人久久| 日韩经典一区二区三区| 日韩av在线网页| 亚洲福利视频久久| 91热福利电影| 亚洲精品不卡在线| 精品亚洲一区二区| 97视频在线观看视频免费视频| 欧美理论电影在线播放| www.99久久热国产日韩欧美.com| 亚洲国产日韩一区| 亚洲美女视频网站| 欧美激情一二区| 国产精品久久久久999| 国产中文日韩欧美| 亚洲图片欧美日产| 中文字幕av一区二区三区谷原希美| 96精品久久久久中文字幕| 在线观看国产精品日韩av| 欧美日韩福利电影| 欧美日韩黄色大片| 日韩在线观看免费网站| 亚洲精品日韩久久久| 久久久久久有精品国产| 国产精品白嫩初高中害羞小美女| 中文字幕久热精品在线视频| 日韩第一页在线| 中文字幕在线国产精品| 亚洲欧美一区二区三区久久| 欧美日韩一区免费| 久久久久久久久亚洲| 国产日韩专区在线| 欧美影院在线播放| 欧美国产日韩中文字幕在线| 亚洲影院色在线观看免费| 国产一区二区黑人欧美xxxx| 亚洲成人黄色在线观看| 亚洲毛片在线看| 国产精品精品久久久久久| 欧美综合第一页| 成人在线视频网站| 欧美日韩美女在线观看| 97超级碰在线看视频免费在线看| 色爱精品视频一区| 国产亚洲精品美女久久久久| 亚洲免费人成在线视频观看| 国产精品三级在线| 91精品在线看| 日韩福利视频在线观看| 成人在线精品视频| 日韩免费在线观看视频| 亚洲欧洲自拍偷拍| 美女少妇精品视频| 97视频在线观看视频免费视频| 国产精品久久久久aaaa九色| 欧美在线视频一区二区| 久久久久久久久国产| 国产精品88a∨| 久99九色视频在线观看| 国产精品久久久久久久久久久新郎| 亚洲精品视频网上网址在线观看| 成人有码在线视频| 成人夜晚看av| 国产精品日日摸夜夜添夜夜av| 亚洲人成在线播放| 日韩欧美在线视频| 日韩性生活视频| 免费91麻豆精品国产自产在线观看| 欧美极品美女视频网站在线观看免费| 亚洲少妇激情视频| 欧美高清视频免费观看| 中文字幕欧美日韩精品| 国产97色在线| 成人av在线亚洲| 亚洲精品永久免费精品| 成人性生交xxxxx网站| 91亚洲va在线va天堂va国| 亚洲伊人一本大道中文字幕| 亚洲欧美国产精品| 韩国一区二区电影| 中文字幕亚洲一区| 尤物九九久久国产精品的分类| 国产精品无码专区在线观看| 国产精品免费视频xxxx| 亚洲成人av在线| 国产精品久久久久久久久久久不卡| 97在线观看免费高清| 国产精品福利在线观看| 久久成人精品一区二区三区| 青青青国产精品一区二区| 国产精品aaaa| 欧美精品在线看| 亚洲激情视频在线观看| 岛国视频午夜一区免费在线观看| 成人亲热视频网站| 久久久中文字幕| 欧美成人三级视频网站| 国产91久久婷婷一区二区| 黑人巨大精品欧美一区免费视频| 97av视频在线| 久久综合九色九九| 一区二区三区精品99久久| 九九热最新视频//这里只有精品| 久久久久久久久久av| 中文字幕亚洲一区| 亚洲视频欧洲视频| 成人春色激情网| 日韩视频永久免费观看| 日韩av男人的天堂| 欧美电影免费看| 欧美国产日韩一区| 国产日产欧美精品| 亚洲第一在线视频| 国产精品嫩草影院久久久| 欧美激情区在线播放| 久久久久久综合网天天| 亚洲国产一区二区三区在线观看| 7777免费精品视频| 国产91精品最新在线播放| 国产精品久久91| 播播国产欧美激情| 久久久久久久久久久免费|