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

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

為C++程序添加文件保存加載功能

2019-11-17 05:10:21
字體:
來源:轉載
供稿:網友
    一、引子

  為什么要浪費時間去設計一個算法來實現數據的文件存儲還要費勁地調試代碼呢?Boost庫可以為你做這些事情。借助于串行化模板,你可以輕易地把數據存儲到你自己定制格式的文件中。本文將教給你如何輕松地存儲數據并回讀數據。


  二、概述

  當你開發一個軟件包時,你總是想集中精力于軟件的功能。而最讓你擔心的是,花費大量的時間寫代碼,而該代碼有可能會應用在另外大量的其他程序中。那正是重用的含義所在,你會希望另外某人已經為你編寫出這樣現成的代碼。

  這類問題的一個很好的例子是給予你的程序存檔的能力。例如,你可能在寫最偉大的天文學程序-在該程序中,你的用戶可以輕易地輸入時間和坐標,你的程序負責繪制當前天空的地圖。但是,假定你賦予你的用戶能夠高亮某些星星,這樣以來它們可以輕易地突出在地圖上。最后,你讓用戶能夠保存他們的配置以備后用。

  你的程序集中于天文學編程。你并不是在寫一個通用庫來保存文檔,所以你不必把大量的時間花在存儲功能上,因為你要專注于程序的天文學特性。假如你是用C++編程,你可以從Boost重用庫得到幫助。為了保存文件,Boost庫包括一個串行化類,正是你需要的。

  假如你成功地創建了你的程序工程,很可能有一個類來包含用戶信息或文檔。例如,你可能有一個類,該類列舉用戶們最喜歡的星星的名字和位置。(請原諒這里的簡化)。這就是你希望用戶能夠保存到磁盤上的數據。究竟,幾乎所有的程序都有文件保存功能。微軟的Word保存文本和格式化數據,而Excel保存工作單數據。一個優秀的地圖程序可以用戶保存喜歡的位置,GPS路線,旅程,等等。

  借助于Boost串行化庫的幫助,實現保存很輕易-所要做是僅僅是設置好你的類,而由庫來負責其它一切-使你專注于真正的工作。

  其思想是很簡單的:你創建了一個包含用戶數據的對象。當預備保存信息時,用戶選擇File|Save As,然后從文件對話框中選擇一個文件名即可。借助于Boost,你的程序就把數據保存到選定的文件中。以后,當用戶重新啟動該程序時,選擇File|Open,選定已保存的文件,你的程序再一次使用Boost-但是這一次重新裝入數據,因此,重新產生了該對象。瞧,用戶數據被回復了!或者,從用戶的角度來看,文檔已被打開。

  下面的例子只是簡單地演示保存和加載一些圖形類。第一個類,Vertex,描述了一個二維的點。第二個類,Polygon,包含一個Vertex實例的容器。第三個類,Drawing,包含一個Polygon的容器。

  想把所有這些都保存到一個文檔中去無疑是一個惡夢-這不是花費時間的地方-你要實現最好的圖形程序設計,因為這是你的專長。好了,讓Boost庫為你做其它一切吧。

  三、串行化一個類

  首先,考慮一下Vertex類。該類是最輕易串行化的一個,因為它不包含其它對象。該類包含兩個值,x和y,且都是double型。我還給該類定義了幾個存取x和y的函數,還有一個dump函數,它負責把x和y的值輸送到控制臺。最后,我包含了兩個構造器,一個是缺省的,另一個用作輸入參數。(為了簡化起見,該例程并沒有做任何實際的繪圖。抱歉?。?br />
  下面最吸引人的部分是必需的代碼行以串行化該類。下面就是該類(注重粗體部分):

class Vertex {
 PRivate:
  friend class boost::serialization::access;
  template
  void serialize(Archive & ar, const unsigned int version)
  {
   ar & x;
   ar & y;
  }
  double x;
  double y;
 public:
  Vertex() {} // 串行化需要一個缺省的構造器
  Vertex(double newX, double newY) : x(newX), y(newY) {}
  double getX() const { return x; }
  double getY() const { return y; }
  void dump() {
   cout << x << " " << y << endl;
  }
};

  注重在程序的最后,我沒有實際地使用缺省的構造器Vertex(),但是串行化庫的確調用了它,因此我需要把它包含進去。

  串行化部分首先串行化庫存取私有成員,非凡是接下來的串行化函數。串行化庫的創建者Robert Ramey指出,你不需要任何的函數,包括在派生類中的那些,調用你的串行化方法;只需由串行化庫來調用即可。因此,為了保護你的類,需要把串行化功能聲明為私有的,然后答應有限制地存取該串行化庫,這通過把類boost::serialization::access聲明為你的類的友元來實現,見代碼。

  接下去是串行化函數,它是一個模板函數。假如你對模板還不太熟悉的話,不要緊:你不需要理解模板部分而照舊可以使之工作。然而,必須確保你理解了串行化功能的核心:

ar & x;
ar & y;

  首先,讓我聲明一下:這兩行代碼并不是聲明參照引用變量,雖然形式上看上去相似。代之的是,它們調用一個&操作符,并且把你的類成員寫入到文件中或者把它們讀進來。是的,你已經正確地認出了;該功能實現了一石二鳥(或者更準確地說,用一套代碼完成了兩件任務)的功效。當你在把一個Vertex對象保存到一個文件中去時,串行化庫調用這個串行化功能;第一行把x的值寫入到文件中,第二行把y的值寫入到文件中。后來,當你把一個Vertex對象從文件中讀回時,第一行實現從文件中讀回x值,第二行實現從文件中讀回y值。

  這是某種非凡的操作符重載!事實上,&字符是一個在串行化庫內部定義的一個操作符。幸好你不需要理解它是如何工作的。

  好,就是那么簡單。下面是一些示例代碼,你可以試著把一個Vertex 對象保存到一個文件中:

Vertex v1(1.5, 2.5);
std::ofstream ofs("myfile.vtx");
boost::archive::text_oarchive oa(ofs);
oa << v1;
ofs.close();

  就是這樣!第一行產生Vertex對象。下面的四行打開一個文件,把一個特定的串行化類與文件相結合,然后寫向文件,最后關閉文件。下面是一段把一個Vertex 對象從文件中讀入的代碼:

Vertex v2;
std::ifstream ifs("myfile.vtx", std::ios::binary);
boost::archive::text_iarchive ia(ifs);
ia >>v2;
ifs.close();
v2.dump();

  這段代碼生成一個Vertex的實例,然后再打開一個文件(這次是為讀取的目的),把一個串行化類與文件相關聯,把對象讀進來,然后關閉文件。最后,代碼輸出Vertex的值。假如你把前面的這兩個程序段放在一個main函數中并運行,你會看到輸出兩個原始值:1.5和2.5。

  注重

  注重我使用的文件擴展名是:.vtx。這并不是一個專門的擴展名;它是我自己定制的擴展名。這聽起來有點愚蠢和瑣碎,但是實際上,我們是在創建自己的文件格式。為了指出這一非凡的文件格式,我使用了擴展名叫.vtx,其意指Vertex。 更多文章 更多內容請看C/C++技術專題  C/C++進階技術文檔專題,或     四、串行化容器

  在我的示例中,一個繪圖對象可以包含多個多邊形對象(我把它們存儲在一個向量中,該向量是標準庫容器模板的一員),每一個多邊形對象可以包含多個對象Vertex(我也用向量存儲它們)。


  串行化庫包括保存數組和容器的功能。因為你可以把指針存儲到數組中,串行化庫也支持指針。請考慮一下:假如你有一個包含Vertex指針的數組,而且你直接把該數組寫入一個文件中,你就會有一堆指針存儲在文件中,而不是實際的Vertex 數據。那些指針僅是些數字(內存位置),當后面接著回讀數據時它們是毫無意義的。所以,該庫十分聰明地從對象中抓取了數據而不是指針。

  考慮到存儲作為容器的對象,你要把每一個類串行化。在串行化方法中,你可以讀取和寫入容器,就象你操作另外一個成員一樣。你的容器可以是簡單的語言本身內存的數組(如Vertex *vertices[10];),或者是來自于標準庫的容器。因為現在是21世紀,我喜歡緊跟時代的步伐,所以我在本例中選擇使用標準庫。

  盡管你可以在你的串行化類中編寫代碼,針對容器和每一個成員;然而,你不必這樣做。作為代勞,庫已十分聰明地自動遍歷容器了。你所有要做是僅是寫出容器,如下,其中vertices是一個容器:

ar & vertices;
  讓庫來做其余的工作吧。相信嗎?下面是類Polygon的代碼,串行化部分以粗體標出:

class Polygon {
 private:
  vectorvertices;
  friend class boost::serialization::access;
  template
  void serialize(Archive & ar, const unsigned int version)
  {
   ar & vertices;
  }
 public:
  void addVertex(Vertex *v) {
   vertices.push_back(v);
  }
  void dump() {
   for_each(vertices.begin(), vertices.end(), mem_fun(&Vertex::dump));
  }
};

  首先,請注重我用一個矢量來存儲布點。(假如你對模板還是個新手,不要緊,只需要把vector當作是存儲指向Vertex 實例的指針的矢量就行,因為其實際上就是如此。)。下一步,在串行化函數中,我不想遍歷該矢量-寫每一個成員。相反,我只是讀寫整個矢量即可:

ar & vertices;
  兩個公共方法的建立,可以用來十分方便地操作該多邊形。第一個addVertex方法,讓你把另外一個結點添加到該多邊形上;它使用了push_back方法,這是把一項加到一個矢量上去的標準方法。Dump函數遍歷該矢量,把每一個矢量寫到標準輸出設備上去。即使對一些很有經驗的C++老手,也可能對下面這一行不太熟悉:

for_each(vertices.begin(), vertices.end(), mem_fun(&Vertex::dump));
  這里用了點小技巧。它不是串行化庫的一部分;它是標準庫的一部分,對于今天的C++程序可以放心使用,沒有任何多余的副作用和經濟問題。單詞for_each實際上是一個函數,它有三個參數:在容器中的起始位置,結束條件以及一個操作容器中每一項都要調用的函數(依靠于你的C++程序實現,你可以要包括頭文件如,’#include ’來得到for_each函數。我使用的是GNU庫,所以用’#include ’語句)。在我的例子中,我用的for_each函數的第三個參數是Vertex 類的dump成員函數。但是有一個問題:你不能只調用一個成員函數本身;你要從一個具體的對象中調用才行。這正是成員函數mem_fun的來源所在。它是一個專門函數(標準庫的一部分),在此與函數for_each一起工作,負責調用具體對象的dump函數。也就是說,它把dump()綁定到for_each當前操縱的Vertex對象上。

  為簡化起見,這里的for_each調用遍歷整個列表中的每一個Vertex,并調用Vertex::dump-所有這些只有一行代碼!

  接下來,Drawing類實際上與Polygon類很相似,除了它包含一些Polygon 對象,而不是包含一個Vertex對象的容器。不是一個大問題。

  下面是完整的程序,包含一些額外的析構器以用于清理內存:

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class Vertex {
 private:
  //串行化代碼開始
  friend class boost::serialization::access;
  template
  void serialize(Archive & ar, unsigned int version)
  {
   ar & x;
   ar & y;
  }
  //結束串行化代碼
  double x;
  double y;
 public:
  Vertex() {} //串行化需要一個缺省的構造器
  ~Vertex() {}
  Vertex(double newX, double newY) : x(newX), y(newY) {}
  double getX() const { return x; }
  double getY() const { return y; }
  void dump() {
   cout << x << " " << y << endl;
  }
};
void delete_vertex(Vertex *v) { delete v; }
class Polygon {
 private:
  vectorvertices;
  friend class boost::serialization::access;
  template
  void serialize(Archive & ar, const unsigned int version)
  {
   ar & vertices;
  }
 public:
  ~Polygon() {
   for_each(vertices.begin(), vertices.end(), delete_vertex);
  }
  void addVertex(Vertex *v) {
   vertices.push_back(v);
  }
  void dump() {
   for_each(vertices.begin(), vertices.end(), mem_fun(&Vertex::dump));
  }
};
void delete_poly(Polygon *p) { delete p; }
class Drawing {
 private:
  vectorpolygons;
  friend class boost::serialization::access;
  template
  void serialize(Archive & ar, const unsigned int version)
  {
   ar & polygons;
  }
 public:
  ~Drawing() {
   for_each(polygons.begin(), polygons.end(), delete_poly);
  }
  void addPolygon(Polygon *p) {
   polygons.push_back(p);
  }
  void dump() {
   for_each(polygons.begin(), polygons.end(), mem_fun(&Polygon::dump));
  }
};
string getFileOpen() {
 //在實際開發中,這將調用一個各種樣的FileOpen 對話框
 return "c:/myfile.grp";
}
string getFileSaveAs() {
 //在實際開發中,這將調用一個各種樣的FileSave 對話框
 return "c:/myfile.grp";
}
void saveDocument(Drawing *doc, const string &filename) {
 ofstream ofs(filename.c_str());
 boost::archive::text_oarchive oa(ofs);
 oa << *doc;
 ofs.close();
}
Drawing *openDocument(const string &filename) {
 Drawing *doc = new Drawing();
 std::ifstream ifs(filename.c_str(), std::ios::binary);
 boost::archive::text_iarchive ia(ifs);
 ia >>*doc;
 ifs.close();
 return doc;
}
int main()
{
 Polygon *poly1 = new Polygon();
 poly1->addVertex(new Vertex(0.1,0.2));
 poly1->addVertex(new Vertex(1.5,1.5));
 poly1->addVertex(new Vertex(0.5,2.9));
 Polygon *poly2 = new Polygon();
 poly2->addVertex(new Vertex(0,0));
 poly2->addVertex(new Vertex(0,1.5));
 poly2->addVertex(new Vertex(1.5,1.5));
 poly2->addVertex(new Vertex(1.5,0));
 Drawing *draw = new Drawing();
 draw->addPolygon(poly1);
 draw->addPolygon(poly2);
 //演示保存一個文檔
 saveDocument(draw, getFileSaveAs());
 // 演示打開一個文檔
 string filename2 = getFileOpen();
 Drawing *doc2 = openDocument(getFileOpen());
 doc2->dump();
 delete draw;
 return 0;
}

  記?。何冶M力脫離開把繪圖對象寫入到文件中去的思想。
代之的是,我只是在概念上把繪制對象當作我的文檔,然后存儲文檔文件和讀回它們。那些文檔文件都具有我為我的程序創立的專門格式,而且我給予它們唯一的文件擴展名.grp,其含義指圖形。

  另外,我創建了幾個幫助函數:getFileSaveAs和getFileOpen。在本例中這些函數僅返回一個硬編碼的字符串形式的文件名。在實際開發中,這些函數一般會分別在菜單項File|Save As和File|Open中被調用;并將會調用系統的File|Open和File|Save對話框。這些對話框將返回一個用戶想使用的字符串形式的文件名。這樣,用戶的看法就同我們一樣了:打開和保存文檔,而不是讀取和寫繪圖對象數據到文檔中。要看清它們在概念上的區別,雖然它們在功能上是相同的。

  五、小結

  借助于Boost庫,給你的軟件增加文件的保存/打開功能相當輕易。假如你想自己試驗這些代碼,你可以在官方站點找到該Boost庫,下載最新版本試驗。

  六、備注

  要使用串行化庫,你最少需要得到該庫的1.32.0版本(早期的版本不包括串行化庫)。注重,在此我不是向你介紹如何安裝Boost庫;網站上提供具體步驟說明如何安裝該庫。假如你使用該串行化庫,你還需要編譯另外幾個該庫需要的.cpp源文件-你可以在boost_1_32_0/libs/serialization/src文件夾下找到它們。還有一個boost_1_32_0/libs/serialization/build 庫,它使用了一種新的創建(build)系統,稱為jamfile,你可以用它來把源文件創建成一個庫。或者,你可以僅把這些源文件添加到你的工程的src目錄下。 更多文章 更多內容請看C/C++技術專題  C/C++進階技術文檔專題,或

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产欧美日韩免费看aⅴ视频| 91久久久久久久久久| 亚洲欧洲在线免费| 国产不卡视频在线| 91av在线免费观看视频| 国产免费一区二区三区在线能观看| 成人黄色av免费在线观看| 日韩美女在线观看一区| 国产丝袜一区二区三区免费视频| 国产精品欧美日韩| 亚洲人成电影在线播放| 夜夜嗨av色综合久久久综合网| 91天堂在线视频| 日本一本a高清免费不卡| 亚洲精品有码在线| 欧美性在线视频| 亚洲在线第一页| 国产精品三级久久久久久电影| 日韩成人av在线| 日韩国产精品亚洲а∨天堂免| 日韩人体视频一二区| 美日韩精品免费观看视频| 日韩经典中文字幕在线观看| 国产精品亚洲视频在线观看| 1769国产精品| 夜夜嗨av一区二区三区免费区| 午夜精品久久久久久99热| 日本伊人精品一区二区三区介绍| 久久精品电影网站| 最近2019中文字幕大全第二页| 亚洲自拍偷拍区| 亚洲第一偷拍网| 美女国内精品自产拍在线播放| 欧美日本亚洲视频| 成人中文字幕+乱码+中文字幕| 久久青草精品视频免费观看| 国产精品视频免费在线| 国产精品视频地址| 精品国产成人在线| 亚洲人成网站色ww在线| 国产美女高潮久久白浆| 欧美成人h版在线观看| 91最新在线免费观看| 色哟哟亚洲精品一区二区| 亚洲欧洲在线播放| 国产精品观看在线亚洲人成网| 美女福利精品视频| 97精品一区二区三区| 蜜月aⅴ免费一区二区三区| 久久久人成影片一区二区三区观看| 中文字幕最新精品| 亚洲免费精彩视频| 国产精品成人播放| 欧美日韩国产中字| 日韩高清欧美高清| 国产综合视频在线观看| 国产午夜精品麻豆| 亚洲精品一区中文字幕乱码| 欧洲亚洲在线视频| 国产精品视频自拍| 欧美亚洲午夜视频在线观看| 日韩大片免费观看视频播放| 55夜色66夜色国产精品视频| 成人夜晚看av| 俺去亚洲欧洲欧美日韩| 日韩av一区二区在线观看| 北条麻妃99精品青青久久| 日韩av在线网址| 午夜精品一区二区三区在线视| 欧美日韩中文字幕在线视频| 免费不卡在线观看av| 欧美精品少妇videofree| 欧美中文字幕视频在线观看| 成人久久一区二区| 国产精品∨欧美精品v日韩精品| 亚洲色图综合网| 最近2019年好看中文字幕视频| 欧美一级大片在线免费观看| 成人av电影天堂| 国语自产偷拍精品视频偷| 欧美日韩中文字幕在线| 国产一区二区三区在线观看网站| 一本色道久久综合狠狠躁篇怎么玩| 欧美午夜美女看片| 在线成人激情视频| 欧美激情国产日韩精品一区18| 欧美国产日韩精品| 精品久久久久久中文字幕一区奶水| 中文字幕亚洲天堂| 成人黄色生活片| 日韩av黄色在线观看| 亚洲色图第三页| 国产69精品久久久| 秋霞成人午夜鲁丝一区二区三区| 国模视频一区二区| 国产精品久久久久不卡| 在线电影中文日韩| 91精品在线一区| 亚洲国产精品人久久电影| 欧美成人精品激情在线观看| 久久久国产一区| 国产精品自产拍在线观| 海角国产乱辈乱精品视频| 欧美在线观看视频| 国产精品久久久999| 亚洲亚裔videos黑人hd| 日韩欧美精品在线观看| 韩国三级电影久久久久久| 精品欧美国产一区二区三区| 亚洲剧情一区二区| 欧美一级片久久久久久久| 欧美老女人在线视频| 91成人福利在线| 国产不卡av在线| 麻豆国产精品va在线观看不卡| 一区二区三区在线播放欧美| 国产精品jvid在线观看蜜臀| 亚洲精品欧美日韩| 久久久在线免费观看| 久久久久九九九九| 亚洲自拍偷拍网址| 2019中文字幕在线观看| 国产欧美韩国高清| 在线电影欧美日韩一区二区私密| 国产精品久久久精品| 成人情趣片在线观看免费| 国产精品极品美女粉嫩高清在线| 日韩福利伦理影院免费| 最好看的2019年中文视频| 国产婷婷色综合av蜜臀av| 欧美亚洲国产另类| 国产精品美女在线| 国产精品丝袜高跟| 91地址最新发布| 亚洲国产成人久久| 久久视频在线看| 成人激情黄色网| 日韩av网站大全| 综合av色偷偷网| 亚洲国产精品电影| 91在线免费视频| 麻豆国产精品va在线观看不卡| 久久成人精品一区二区三区| 亚洲bt天天射| 成人福利视频网| 亚洲欧美日本精品| 国产综合在线观看视频| 91视频88av| 亚洲区在线播放| 中文字幕综合在线| 久久久亚洲影院| 国产区精品视频| 国产成人av网址| 久久精品国产亚洲精品2020| 91在线网站视频| 日韩中文字幕久久| 精品久久久久久久久久久久| 日本一区二区不卡| 久久久精品一区| 91免费视频国产| 国产精品免费一区| 91精品啪在线观看麻豆免费| 57pao精品| 久久国产精品电影|