第6章基于C流類庫的文件輸入輸出和程序的組織課件_第1頁
第6章基于C流類庫的文件輸入輸出和程序的組織課件_第2頁
第6章基于C流類庫的文件輸入輸出和程序的組織課件_第3頁
第6章基于C流類庫的文件輸入輸出和程序的組織課件_第4頁
第6章基于C流類庫的文件輸入輸出和程序的組織課件_第5頁
已閱讀5頁,還剩101頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

第6章基于C++流類庫的文件輸入/輸出及C++程序的組織第6章基于C++流類庫的文件輸入/輸出及C++程序的組文件是指存放在外部介質(zhì)(如硬盤、U盤、光盤等)上的數(shù)據(jù)的集合。根據(jù)數(shù)據(jù)組織的形式,文件可分為文本文件(ASCII文件)和二進制文件。在C++中,可以利用從C語言標準庫保留下來的輸入/輸出函數(shù)庫進行文件的輸入/輸出操作,也可以利用C++的I/O流類庫進行文件的輸入/輸出操作。2文件是指存放在外部介質(zhì)(如硬盤、U盤、光盤等)上的數(shù)據(jù)的集合6.1C++流類庫在C++中,數(shù)據(jù)的輸入/輸出(如從鍵盤讀取數(shù)據(jù)、在顯示器上顯示數(shù)據(jù)、從文件讀取數(shù)據(jù)、將數(shù)據(jù)寫入文件等)可基于流類庫完成。36.1C++流類庫在C++中,數(shù)據(jù)的輸入/輸出(如從鍵盤讀6.1.1C++的流“流”是指數(shù)據(jù)從一個地方到另一個地方的流動抽象。例如,將數(shù)據(jù)從鍵盤或文件讀入內(nèi)存時,稱為“輸入流”;將數(shù)據(jù)從內(nèi)存輸出到顯示器或文件中時,稱為“輸出流”??梢詮牧髦蝎@取數(shù)據(jù),也可以向流中添加數(shù)據(jù)。從流中獲取數(shù)據(jù)的操作稱為“提取”操作,向流中添加數(shù)據(jù)的操作稱為“插入”操作。C++提供了4個預定義的標準流對象:cin、cout、cerr和clog。其中,cin是istream類的對象,用于處理標準輸入操作,默認指鍵盤輸入;cout是ostream類的對象,用于處理標準輸出操作,默認指顯示器輸出。46.1.1C++的流“流”是指數(shù)據(jù)從一個地方到另一個地方的cin、cout和clog三個流對象帶有緩沖區(qū)。緩沖區(qū)的概念是:對于輸出,只有當緩沖區(qū)滿后才能將緩沖區(qū)的信息進行輸出;對于輸入,只有輸入一行結(jié)束,才開始從緩沖區(qū)讀取數(shù)據(jù)。當希望緩沖區(qū)的內(nèi)容立即輸出時,可利用flush和endl。標準流對象常使用提取運算符“>>”和插入運算符“<<”進行輸入和輸出操作。5cin、cout和clog三個流對象帶有緩沖區(qū)。緩沖區(qū)的概念6.1.2C++的流類庫在C++標準庫中,C++流類庫使用類模板進行實現(xiàn)。流類模板具有層次結(jié)構(gòu),見下圖。6類istream是basic_istream類模板的實例化類類ostream是basic_ostream類模板的實例化類類iftream是basic_ifstream類模板的實例化類類ofstream是basic_ofstream類模板的實例化類類fstream是basic_fstream類模板的實例化類6.1.2C++的流類庫在C++標準庫中,C++流類庫使用6.2利用C++文件流類進行文本文件的讀寫

可通過C++的文件流類ifstream、ofstream和fstream進行文本文件的讀取和保存。76.2利用C++文件流類進行文本文件的讀寫可通過C++的【例6-1】

文本文件的讀寫在本例中,定義了3個學生對象Student1、Student2和Student3。首先進行了打開文件操作,將這些學生對象的信息以文本數(shù)據(jù)的形式寫入了文本文件“StudentInfo.txt”,再通過讀取該文件,將這些信息讀入了另外3個學生對象Student1_1、Student2_1和Student3_1中,最后將Student1_1、Student2_1和Student3_1的信息進行了輸出。8【例6-1】文本文件的讀寫在本例中,定義了3個學生對象S#include<iostream>#include<fstream>usingnamespacestd;classCDate {……};……classCPerson {protected: char*m_strName; ……public: ……

virtualvoidWriteFile(ofstream&fs);//數(shù)據(jù)寫入文件

virtualvoidReadFile(ifstream&fs);//從文件中讀取數(shù)據(jù)};……9人員類輸出文件流類輸入文件流類日期類#include<iostream>9人員類輸出文件流類輸voidCPerson::WriteFile(ofstream&fs){ fs<<m_strName<<'\n'<<m_strID <<' '<<m_cSex<<' '<<m_Birthday.GetYear() <<' '<<m_Birthday.GetMonth() <<' '<<m_Birthday.GetDay()<<' ';}10利用插入運算符將人員屬性信息寫到輸出文件流fs中voidCPerson::WriteFile(ofstrevoidCPerson::ReadFile(ifstream&fs){ intnYear,nMonth,nDay; charstrName[256],strID[12]; fs.getline(strName,256); fs>>strID>>m_cSex>>nYear>>nMonth>>nDay;

delete[]m_strname; m_strName=newchar[strlen(strName)+1]; strcpy(m_strName,strName); delete[]m_strID; m_strID=newchar[strlen(strID)+1]; strcpy(m_strID,strID); CDateBirthday(nYear,nMonth,nDay); m_Birthday=Birthday;}}11利用提取運算符從輸入文件流fs讀取信息從輸入文件流fs中讀取一行信息voidCPerson::ReadFile(ifstreaclassCStudent:publicCPerson { staticunsignedlongm_nCount; protected: char*m_strMajor; public: ……

voidWriteFile(ofstream&fs);//數(shù)據(jù)寫入文件

voidReadFile(ifstream&fs);//從文件中讀取數(shù)據(jù)};……voidCStudent::WriteFile(ofstream&fs){ CPerson::WriteFile(fs); fs<<m_strMajor<<endl;}12classCStudent:publicCPersonvoidCStudent::ReadFile(ifstream&fs){ CPerson::ReadFile(fs); charstrMajor[256]; fs.getline(strMajor,256); delete[]m_strMajor; m_strMajor=newchar[strlen(strMajor)+1]; strcpy(m_strMajor,strMajor);}13voidCStudent::ReadFile(ifstreunsignedlongCStudent::m_nCount=0; intmain(){ CStudentStudent1("李江","50200900825",'0',1991,3,7,"計算機科學與技術(shù)"); CStudentStudent2("趙梅","50200900826",'1',1991,6,8,"計算機科學與技術(shù)"); CStudentStudent3("武峰","50200900827",'0',1990,5,6,"計算機科學與技術(shù)");

ofstreamfout("StudentInfo.txt");

if(fout.fail())

{ cout<<"Openfilefailture!"<<endl; return1; }

Student1.WriteFile(fout); Student2.WriteFile(fout); Student3.WriteFile(fout);

fout.close();

14定義輸出文件流對象fout并通過它打開或創(chuàng)建文件StudentInfo.txt如果文件打開或創(chuàng)建失敗,則退出將學生的信息寫到輸出文件流對象fout中關(guān)閉文件unsignedlongCStudent::m_nCou

ifstreamfin("StudentInfo.txt");

if(fin.fail()) { cout<<"Openfilefailture!"<<endl; return1; } CStudentStudent1_1,Student2_1,Student3_1;

Student1_1.ReadFile(fin); Student2_1.ReadFile(fin); Student3_1.ReadFile(fin);

fin.close(); Student1_1.DisplayInfo(); cout<<endl; Student2_1.DisplayInfo(); cout<<endl; Student3_1.DisplayInfo(); cout<<endl; return0;}15定義輸入文件流對象fin并通過它打開文件StudentInfo.txt如果文件打開失敗,則退出將輸入流文件對象fin中的數(shù)據(jù)讀到學生對象中關(guān)閉文件輸出學生信息 ifstreamfin("StudentInfo.txt程序的運行結(jié)果如下:姓名:李江編號:50200900825性別:男出生日期:1991,3,7專業(yè):計算機科學與技術(shù)姓名:趙梅編號:50200900826性別:女出生日期:1991,6,8專業(yè):計算機科學與技術(shù)姓名:武峰編號:50200900827性別:男出生日期:1990,5,6專業(yè):計算機科學與技術(shù)如果用記事本程序打開文本文件“StudentInfo.txt”,就會看到下圖所示的內(nèi)容:16程序的運行結(jié)果如下:16本例中對文件的操作過程①打開文件StudentInfo.txt,如果該文件不存在,則創(chuàng)建一個文件名為StudentInfo.txt的新文件。②將學生信息以文本的形式寫到文件中。③關(guān)閉此文件。④重新打開StudentInfo.txt文件。⑤將文件中的數(shù)據(jù)讀到學生對象中。⑥關(guān)閉此文件。17本例中對文件的操作過程①打開文件StudentInfo.說明

(1)C++提供了3個用于文件輸入/輸出的文件流類,如下所示。 ①ifstream:輸入文件流類,用于文件的輸入。 ②ofstream:輸出文件流類,用于文件的輸出。 ③fstream:輸入/輸出文件流類,用于文件的輸入/輸出。 在使用這些文件流類時,通常要在程序中包含頭文件fstream。例如:

#include<fstream>18說明(1)C++提供了3個用于文件輸入/輸出的文件流類,如(2)文件流類對象的定義和文件的打開①在利用文件流類進行文件操作時,首先要建立流類的對象。例如:

ifstreamfin; ofstreamfout; fstreamfin_out;②可以通過流類對象的構(gòu)造函數(shù)打開文件,例如:

ofstreamfout("StudentInfo.txt");該語句定義了輸出文件流類的對象fout,并通過其構(gòu)造函數(shù)打開了用于輸出的文件StudentInfo.txt。

再例如:

ifstreamfin("StudentInfo.txt");該語句定義了輸入文件流類的對象fin,并通過其構(gòu)造函數(shù)打開了用于輸入的文件StudentInfo.txt。19(2)文件流類對象的定義和文件的打開①在利用文件流類進行文③通過文件流對象的成員函數(shù)open()打開文件調(diào)用該函數(shù)的一般形式為:

文件流對象.open(文件名,打開方式);其中,“文件名”可以包括路徑(如 “D:\\data\\StudentInfo.txt”),如果不指明路徑,則默認為當前目錄下的文件?!按蜷_方式”決定如何打開文件,如表6-1所示。20③通過文件流對象的成員函數(shù)open()打開文件調(diào)用該函數(shù)的表6-1文件的打開方式方式功能ios::app打開一個已存在的文件,以將數(shù)據(jù)添加到文件的尾部。這種方式打開的文件只能用于輸出ios::ate打開一個已存文件,并將文件指針移到文件的尾部ios::binary以二進制的形式打開文件ios::in打開一個文件,進行文件輸入操作ios::out打開一個文件,進行文件輸出操作ios::trunc打開一個文件,如果該文件已存在,則清除文件的內(nèi)容,文件的長度變?yōu)榱?1表6-1文件的打開方式方式功能ios::app打開一個已存●如果用ifstream類來定義一個流對象,則隱含為輸入流,不必再添加ios::in說明;如果用ofstream類來定義一個流對象,則隱含為輸出流,不必再添加ios::out說明。 例如:

ifstreamin; in.open("test.dat");//等同于in.open("test.dat",ios::in); ofstreamout; out.open("test.dat");//等同于out.open("test.dat",ios::out)●當指定“ios::out”方式后,隱含為“ios::trunc”方式,即如果打開的輸出文件已存在,則自動清空該文件的內(nèi)容?!袢绻募蜷_時需要多種打開方式的組合,則應使用“|”(位或操作符)將幾種打開方式組合在一起。例如,可采用以下方式打開一個能夠進行輸入和輸出的二進制文件。

fstreamfin_out; fin_out.open("test.dat",ios::in|ios::out|ios::binary);22●如果用ifstream類來定義一個流對象,則隱含為輸入流④在進行文件打開操作時,應該判斷文件打開是否成功,見下面的語句。

if(fout.fail()) cout<<"Openfilefailture!"<<endl;

fail()函數(shù)是basic_ios類模板(見圖6-1)的成員函數(shù)。在這里,當返回值為true時,說明出現(xiàn)了文件打開錯誤。23④在進行文件打開操作時,應該判斷文件打開是否成功,見下面的(3)文本文件的讀寫●可通過提取運算符“>>”和插入運算符“<<”對文件流對象進行操作,實現(xiàn)文件的讀和寫。●getline()函數(shù)

fs.getline(strName,256);//從文件中讀取姓名信息

函數(shù)getline()是basic_istream的成員函數(shù),其函數(shù)聲明是:basic_istream&getline(char_type*_Str,streamsize_Count);

其含義是:從文件流中讀取_Count個字節(jié)到_Str所指的內(nèi)存中,如果還沒有讀取_Count個字節(jié)就遇到回車符'\n',則讀取過程中止。24(3)文本文件的讀寫●可通過提取運算符“>>”和插入運算符“(4)文件的關(guān)閉在對文件的讀寫操作完成后,應關(guān)閉文件。通過關(guān)閉操作,文件流對象與相應的物理文件進行了脫離。如果不進行文件的關(guān)閉,則可能造成文件數(shù)據(jù)的丟失。關(guān)閉文件可使用流類的成員函數(shù)close()完成,例如:fout.close();fin.close();25(4)文件的關(guān)閉在對文件的讀寫操作完成后,應關(guān)閉文件。通過關(guān)6.3利用C++文件流類進行二進制文件的讀寫當進行二進制文件的讀寫時,在打開文件時要使用“ios::binary”來指定以二進制的形式進行文件流的操作。對二進制文件的讀寫可使用C++流類的get()、put()成員函數(shù)或read()、write()成員函數(shù)。這些函數(shù)也可以用于文本文件的讀寫。下面首先通過read()、write()函數(shù)改寫例6-1,實現(xiàn)二進制文件的讀寫,然后介紹get()、put()函數(shù)的使用方法。266.3利用C++文件流類進行二進制文件的讀寫當進行二進制6.3.1利用write()和read()函數(shù)實現(xiàn)二進制文件的讀寫 【例6-2】

二進制文件的讀寫。 本例將學生信息寫入二進制文件,然后再從二進制文件中讀出學生信息并進行顯示。本例在例6-1的代碼基礎(chǔ)上進行修改,主要代碼如下所示。276.3.1利用write()和read()函數(shù)實現(xiàn)二進制……voidCPerson::WriteFile(ofstream&fs){ unsignedcharucStrLength; //計算姓名字符串(包括字符串結(jié)束符)的長度 ucStrLength=strlen(m_strName)+1; //寫入姓名字符串的長度

fs.write((char*)&ucStrLength,sizeof(ucStrLength)); //寫入姓名字符串

fs.write(m_strName,ucStrLength); ucStrLength=strlen(m_strID)+1; //寫入編號字符串的長度

fs.write((char*)&ucStrLength,sizeof(ucStrLength));28……28//寫入編號字符串fs.write(m_strID,ucStrLength);//寫入性別字符fs.write(&m_cSex,sizeof(m_cSex));//寫入出生日期fs.write((char*)&m_Birthday,sizeof(m_Birthday));}29//寫入編號字符串29voidCPerson::ReadFile(ifstream&fs){ unsignedcharucStrLength; //讀入姓名字符串的長度

fs.read((char*)&ucStrLength,sizeof(ucStrLength)); delete[]m_strName; m_strName=newchar[ucStrLength]; //讀入姓名字符串

fs.read(m_strName,ucStrLength);

//讀入編號字符串的長度 fs.read((char*)&ucStrLength,sizeof(ucStrLength)); delete[]m_strID; m_strID=newchar[ucStrLength];

fs.read(m_strID,ucStrLength);//讀入編號字符串 fs.read(&m_cSex,sizeof(m_cSex)); fs.read((char*)&m_Birthday,sizeof(m_Birthday));}30voidCPerson::ReadFile(ifstrea……voidCStudent::WriteFile(ofstream&fs){

CPerson::WriteFile(fs); unsignedcharucStrLength; //計算專業(yè)字符串(包括字符串結(jié)束符)的長度 ucStrLength=strlen(m_strMajor)+1; //寫入專業(yè)字符串長度

fs.write((char*)&ucStrLength,sizeof(ucStrLength)); //寫入專業(yè)字符串

fs.write(m_strMajor,ucStrLength);}31……31voidCStudent::ReadFile(ifstream&fs){

CPerson::ReadFile(fs); unsignedcharucStrLength; //讀入專業(yè)字符串長度

fs.read((char*)&ucStrLength,sizeof(ucStrLength)); delete[]m_strMajor; m_strMajor=newchar[ucStrLength); //讀入專業(yè)字符串

fs.read(m_strMajor,ucStrLength);}32voidCStudent::ReadFile(ifstreunsignedlongCStudent::m_nCount=0;intmain(){ CStudentStudent1("李江","50200900825",'0',1991,3,7,"計算機科學與技術(shù)"); CStudentStudent2("趙梅","50200900826",'1',1991,6,8,"計算機科學與技術(shù)"); CStudentStudent3("武峰","50200900827",'0',1990,5,6,"計算機科學與技術(shù)");

ofstreamfout("StudentInfo.dat",ios::binary);

if(fout.fail()) { cout<<"Openfilefailture!"<<endl; return1; } Student1.WriteFile(fout); Student2.WriteFile(fout); Student3.WriteFile(fout); fout.close();33定義輸出文件流對象fout并通過它打開或創(chuàng)建二進制文件StudentInfo.dat如果文件打開或創(chuàng)建失敗,則退出將學生的信息寫到輸出文件流對象fout中關(guān)閉文件unsignedlongCStudent::m_nCou

ifstreamfin("StudentInfo.dat",ios::binary); if(fin.fail()) { cout<<"Openfilefailture!"<<endl; return1; } CStudentStudent1_1,Student2_1,Student3_1;

Student1_1.ReadFile(fin); Student2_1.ReadFile(fin); Student3_1.ReadFile(fin); fin.close(); Student1_1.DisplayInfo(); cout<<endl; Student2_1.DisplayInfo(); cout<<endl; Student3_1.DisplayInfo(); cout<<endl; return0;}34定義輸入文件流對象fin并通過它打開二進制文件StudentInfo.dat如果文件打開失敗,則退出將輸入流文件對象fin中的數(shù)據(jù)讀到學生對象中關(guān)閉文件輸出學生信息 ifstreamfin("StudentInfo.dat程序的運行結(jié)果如下:姓名:李江編號:50200900825性別:男出生日期:1991,3,7專業(yè):計算機科學與技術(shù)姓名:趙梅編號:50200900826性別:女出生日期:1991,6,8專業(yè):計算機科學與技術(shù)姓名:武峰編號:50200900827性別:男出生日期:1990,5,6專業(yè):計算機科學與技術(shù)如果用記事本程序打開二進制文件“StudentInfo.dat”,就會看到下圖所示的內(nèi)容:35程序的運行結(jié)果如下:35說明(1)在進行二進制文件的讀寫之前,首先要以二進制的形式打開文件,見下面的語句。ofstreamfout("StudentInfo.dat",ios::binary);ifstreamfin("StudentInfo.dat",ios::binary);(2)write()是ostream類的成員函數(shù),其函數(shù)原型如下:ostream&write(constchar*,int);

在進行文件操作時,函數(shù)的第1個參數(shù)表示要寫入文件的數(shù)據(jù)所在的內(nèi)存起始地址,第2個參數(shù)是要寫入文件的字節(jié)數(shù)。(3)read()是istream類的成員函數(shù),其函數(shù)形式如下:

istream&read(char*,int);

在進行文件操作時,函數(shù)的第1個參數(shù)表示從文件中讀入的數(shù)據(jù)所存放的內(nèi)存空間的起始地址,函數(shù)的第2個參數(shù)表示從文件中讀入的字節(jié)數(shù)。36說明(1)在進行二進制文件的讀寫之前,首先要以二進制的形式6.3.2利用get()和put()函數(shù)實現(xiàn)二進制文件的讀寫get()函數(shù)是輸入流類istream的成員函數(shù),可以通過它從文件流對象中讀取數(shù)據(jù),每次讀出一個字節(jié)(字符)。put()函數(shù)是輸出流類ostream的成員函數(shù),可以通過它向文件流對象中寫入數(shù)據(jù),每次寫入一個字節(jié)(字符)。下面給出一個利用get()和put()函數(shù)讀寫二進制文件的例子。376.3.2利用get()和put()函數(shù)實現(xiàn)二進制文件的【例6-3】

將0~9共10個數(shù)寫入二進制文件,然后從該文件中讀取這些數(shù)并顯示。#include<iostream>#include<fstream>usingnamespacestd;intmain(){

ofstreamfout("number.dat",ios::binary); if(fout.fail()) { cout<<"Openfilefailture!"<<endl; return1; }38定義輸出文件流對象fout并通過它打開或創(chuàng)建二進制文件number.dat如果文件打開或創(chuàng)建失敗,則退出【例6-3】將0~9共10個數(shù)寫入二進制文件,然后從該文 for(unsignedcharc=0;c<10;c++)

fout.put(c);

fout.close();

ifstreamfin("number.dat",ios::binary);

if(fin.fail()) { cout<<"Openfilefailture!"<<endl; return1; }39將0~9這10個數(shù)寫到輸出文件流對象fout中向文件流中寫入1個字節(jié)關(guān)閉文件定義輸入文件流對象fin并通過它打開文件number.dat如果文件打開失敗,則退出39將0~9這10個數(shù)寫到輸出文件流對象fout中向文件流中 charch; while(1) {

fin.get(ch);

if(fin.eof()) break; cout<<(int)ch<<''; }

fin.close(); return0;}40從輸入流文件對象fin中讀取數(shù)據(jù)并顯示從文件流中讀取1個字節(jié)判斷是否到達了文件尾以整數(shù)的形式輸出字符變量ch的值關(guān)閉文件程序的運行結(jié)果如下:012345678940從輸入流文件對象fin中讀取數(shù)據(jù)并顯示從文件流中讀取1個說明(1)本例中使用的put()函數(shù)的原型是:

ostream&put(char)(2)本例中使用的get()函數(shù)的原型是:

istream&get(char&)(3)eof()函數(shù)用于判斷是否到達了文件尾。函數(shù)返回值為true說明到達了文件尾,返回值為false說明未到達文件尾。41說明(1)本例中使用的put()函數(shù)的原型是:41

6.4C++程序的組織

42

6.4C++程序的組織

42C++程序的組織方式通常,C++程序可按照下面三類文件進行組織:(1)將類的聲明作為頭文件來保存,文件擴展名為.h或.hpp。(2)將類的成員函數(shù)定義單獨組成一個文件,文件擴展名為.cpp。(3)在主程序文件中包含main()函數(shù),由主程序文件完成對各個類對象的調(diào)用,該文件擴展名為.cpp。43C++程序的組織方式通常,C++程序可按照下面三類文件進行重新對大學人員信息管理系統(tǒng)程序進行組織

(改寫例4-8)44程序的組織方式說明對應的文件CDate類Date.h,Date.cppCPerson類Person.h,Person.cppCStudent類Student.h,Student.cppCEmployee類Employee.h,Employee.cppCGraStudent類GraStudent.h,GraStudent.cpp主程序(包含main()函數(shù))UMIS.cpp重新對大學人員信息管理系統(tǒng)程序進行組織

(改寫例4-8)4Date.h文件的結(jié)構(gòu)#if!defined__DATE_H__ #define__DATE_H__classCDate{ intm_nYear; intm_nMonth; intm_nDay;public: CDate(intnYear,intnMonth,intnDay); ……};#endif45通過編譯預處理命令防止對CDate類的重復聲明#!defined和

#endif控制源代碼要編譯的部分Date.h文件的結(jié)構(gòu)#if!defined__DATDate.cpp文件的結(jié)構(gòu)#include"Date.h"#include<iostream>usingnamespacestd;CDate::CDate(intnYear,intnMonth,intnDay){ m_nYear=nYear; m_nMonth=nMonth; m_nDay=nDay;}……//CDate類其他成員函數(shù)的定義46Date.cpp文件的結(jié)構(gòu)#include"Date.h編譯預處理命令#if!defined、#define和#endif這些預處理命令的功能是當一個文件中多次(直接或間接)包含include"Date.h"語句時,使得CDate類的聲明僅僅被展開一次,而不會被重復展開,從而避免聲明沖突。47編譯預處理命令#if!defined、#define和#e條件編譯命令#if命令和#endif命令屬于條件編譯命令,用于控制源程序中被編譯的部分。條件編譯是指當滿足一定的條件時,才對程序的某部分進行編譯。#if命令和#endif命令要配套使用。在上面的代碼中,使用了下面的形式:#if!defined<標識>#define<標識>……#endif其中,<標識>的命名規(guī)則通常是將頭文件名大寫,前后加下劃線,并將文件名中的“.”也變成下劃線。48條件編譯命令#if命令和#endif命令屬于條件編譯命令,用說明代碼中,“#if!defined__DATE_H__”的含義是:如果沒有定義__DATE_H__標識符,則進行下面程序部分的編譯,直到遇到#endif命令?!?define__DATE_H__”的含義是定義標識符__DATE_H__。通過這些預處理命令的控制,當?shù)?次將頭文件Date.h展開時,“#if!defined__DATE_H__”的返回值為真,定義__DATE_H__標識符,加入CDate類的聲明。當不是第1次展開Date.h文件時,由于__DATE_H__標識符已經(jīng)被定義,因此“#if!defined__DATE_H__”的返回值為假,不再編譯下面的程序部分,這樣就避免了類聲明的沖突。49說明代碼中,“#if!defined__DATE_H__Person.h文件的結(jié)構(gòu)#if!defined__PERSON_H__#define__PERSON_H__#include"Date.h"classCPerson{ ……}; #endif50Person.h文件的結(jié)構(gòu)#if!defined__PPerson.cpp文件的結(jié)構(gòu)#include"Person.h"#include<iostream>usingnamespacestd;CPerson::CPerson(char*strName,char*strID,charcSex,intnYear,intnMonth,intnDay):m_Birthday(nYear,nMonth,nDay){ ……}……//CPerson類其它成員函數(shù)的定義51Person.cpp文件的結(jié)構(gòu)#include"Pers主程序文件(UMIS.cpp)的結(jié)構(gòu)#include"Person.h"#include"Student.h"#include"Employee.h"#include"GraStudent.h"#include<iostream>usingnamespacestd;unsignedlongCStudent::m_nCount=0;unsignedlongCEmployee::m_nCount=0;unsignedlongCGraStudent::m_nCount=0;intmain(){ …… return0;}52主程序文件(UMIS.cpp)的結(jié)構(gòu)#include"PC++程序設(shè)計思路通過面向?qū)ο蟪绦蛟O(shè)計方法,程序編制顯得相對自然和簡捷。首先定義各個類,然后定義若干個對象,然后調(diào)用其成員函數(shù),由成員函數(shù)來完成程序員所規(guī)定的操作(即讓對象表現(xiàn)自己)。53C++程序設(shè)計思路通過面向?qū)ο蟪绦蛟O(shè)計方法,程序編制顯得相對

第6章基于C++流類庫的文件輸入/輸出及C++程序的組織第6章基于C++流類庫的文件輸入/輸出及C++程序的組文件是指存放在外部介質(zhì)(如硬盤、U盤、光盤等)上的數(shù)據(jù)的集合。根據(jù)數(shù)據(jù)組織的形式,文件可分為文本文件(ASCII文件)和二進制文件。在C++中,可以利用從C語言標準庫保留下來的輸入/輸出函數(shù)庫進行文件的輸入/輸出操作,也可以利用C++的I/O流類庫進行文件的輸入/輸出操作。55文件是指存放在外部介質(zhì)(如硬盤、U盤、光盤等)上的數(shù)據(jù)的集合6.1C++流類庫在C++中,數(shù)據(jù)的輸入/輸出(如從鍵盤讀取數(shù)據(jù)、在顯示器上顯示數(shù)據(jù)、從文件讀取數(shù)據(jù)、將數(shù)據(jù)寫入文件等)可基于流類庫完成。566.1C++流類庫在C++中,數(shù)據(jù)的輸入/輸出(如從鍵盤讀6.1.1C++的流“流”是指數(shù)據(jù)從一個地方到另一個地方的流動抽象。例如,將數(shù)據(jù)從鍵盤或文件讀入內(nèi)存時,稱為“輸入流”;將數(shù)據(jù)從內(nèi)存輸出到顯示器或文件中時,稱為“輸出流”??梢詮牧髦蝎@取數(shù)據(jù),也可以向流中添加數(shù)據(jù)。從流中獲取數(shù)據(jù)的操作稱為“提取”操作,向流中添加數(shù)據(jù)的操作稱為“插入”操作。C++提供了4個預定義的標準流對象:cin、cout、cerr和clog。其中,cin是istream類的對象,用于處理標準輸入操作,默認指鍵盤輸入;cout是ostream類的對象,用于處理標準輸出操作,默認指顯示器輸出。576.1.1C++的流“流”是指數(shù)據(jù)從一個地方到另一個地方的cin、cout和clog三個流對象帶有緩沖區(qū)。緩沖區(qū)的概念是:對于輸出,只有當緩沖區(qū)滿后才能將緩沖區(qū)的信息進行輸出;對于輸入,只有輸入一行結(jié)束,才開始從緩沖區(qū)讀取數(shù)據(jù)。當希望緩沖區(qū)的內(nèi)容立即輸出時,可利用flush和endl。標準流對象常使用提取運算符“>>”和插入運算符“<<”進行輸入和輸出操作。58cin、cout和clog三個流對象帶有緩沖區(qū)。緩沖區(qū)的概念6.1.2C++的流類庫在C++標準庫中,C++流類庫使用類模板進行實現(xiàn)。流類模板具有層次結(jié)構(gòu),見下圖。59類istream是basic_istream類模板的實例化類類ostream是basic_ostream類模板的實例化類類iftream是basic_ifstream類模板的實例化類類ofstream是basic_ofstream類模板的實例化類類fstream是basic_fstream類模板的實例化類6.1.2C++的流類庫在C++標準庫中,C++流類庫使用6.2利用C++文件流類進行文本文件的讀寫

可通過C++的文件流類ifstream、ofstream和fstream進行文本文件的讀取和保存。606.2利用C++文件流類進行文本文件的讀寫可通過C++的【例6-1】

文本文件的讀寫在本例中,定義了3個學生對象Student1、Student2和Student3。首先進行了打開文件操作,將這些學生對象的信息以文本數(shù)據(jù)的形式寫入了文本文件“StudentInfo.txt”,再通過讀取該文件,將這些信息讀入了另外3個學生對象Student1_1、Student2_1和Student3_1中,最后將Student1_1、Student2_1和Student3_1的信息進行了輸出。61【例6-1】文本文件的讀寫在本例中,定義了3個學生對象S#include<iostream>#include<fstream>usingnamespacestd;classCDate {……};……classCPerson {protected: char*m_strName; ……public: ……

virtualvoidWriteFile(ofstream&fs);//數(shù)據(jù)寫入文件

virtualvoidReadFile(ifstream&fs);//從文件中讀取數(shù)據(jù)};……62人員類輸出文件流類輸入文件流類日期類#include<iostream>9人員類輸出文件流類輸voidCPerson::WriteFile(ofstream&fs){ fs<<m_strName<<'\n'<<m_strID <<' '<<m_cSex<<' '<<m_Birthday.GetYear() <<' '<<m_Birthday.GetMonth() <<' '<<m_Birthday.GetDay()<<' ';}63利用插入運算符將人員屬性信息寫到輸出文件流fs中voidCPerson::WriteFile(ofstrevoidCPerson::ReadFile(ifstream&fs){ intnYear,nMonth,nDay; charstrName[256],strID[12]; fs.getline(strName,256); fs>>strID>>m_cSex>>nYear>>nMonth>>nDay;

delete[]m_strname; m_strName=newchar[strlen(strName)+1]; strcpy(m_strName,strName); delete[]m_strID; m_strID=newchar[strlen(strID)+1]; strcpy(m_strID,strID); CDateBirthday(nYear,nMonth,nDay); m_Birthday=Birthday;}}64利用提取運算符從輸入文件流fs讀取信息從輸入文件流fs中讀取一行信息voidCPerson::ReadFile(ifstreaclassCStudent:publicCPerson { staticunsignedlongm_nCount; protected: char*m_strMajor; public: ……

voidWriteFile(ofstream&fs);//數(shù)據(jù)寫入文件

voidReadFile(ifstream&fs);//從文件中讀取數(shù)據(jù)};……voidCStudent::WriteFile(ofstream&fs){ CPerson::WriteFile(fs); fs<<m_strMajor<<endl;}65classCStudent:publicCPersonvoidCStudent::ReadFile(ifstream&fs){ CPerson::ReadFile(fs); charstrMajor[256]; fs.getline(strMajor,256); delete[]m_strMajor; m_strMajor=newchar[strlen(strMajor)+1]; strcpy(m_strMajor,strMajor);}66voidCStudent::ReadFile(ifstreunsignedlongCStudent::m_nCount=0; intmain(){ CStudentStudent1("李江","50200900825",'0',1991,3,7,"計算機科學與技術(shù)"); CStudentStudent2("趙梅","50200900826",'1',1991,6,8,"計算機科學與技術(shù)"); CStudentStudent3("武峰","50200900827",'0',1990,5,6,"計算機科學與技術(shù)");

ofstreamfout("StudentInfo.txt");

if(fout.fail())

{ cout<<"Openfilefailture!"<<endl; return1; }

Student1.WriteFile(fout); Student2.WriteFile(fout); Student3.WriteFile(fout);

fout.close();

67定義輸出文件流對象fout并通過它打開或創(chuàng)建文件StudentInfo.txt如果文件打開或創(chuàng)建失敗,則退出將學生的信息寫到輸出文件流對象fout中關(guān)閉文件unsignedlongCStudent::m_nCou

ifstreamfin("StudentInfo.txt");

if(fin.fail()) { cout<<"Openfilefailture!"<<endl; return1; } CStudentStudent1_1,Student2_1,Student3_1;

Student1_1.ReadFile(fin); Student2_1.ReadFile(fin); Student3_1.ReadFile(fin);

fin.close(); Student1_1.DisplayInfo(); cout<<endl; Student2_1.DisplayInfo(); cout<<endl; Student3_1.DisplayInfo(); cout<<endl; return0;}68定義輸入文件流對象fin并通過它打開文件StudentInfo.txt如果文件打開失敗,則退出將輸入流文件對象fin中的數(shù)據(jù)讀到學生對象中關(guān)閉文件輸出學生信息 ifstreamfin("StudentInfo.txt程序的運行結(jié)果如下:姓名:李江編號:50200900825性別:男出生日期:1991,3,7專業(yè):計算機科學與技術(shù)姓名:趙梅編號:50200900826性別:女出生日期:1991,6,8專業(yè):計算機科學與技術(shù)姓名:武峰編號:50200900827性別:男出生日期:1990,5,6專業(yè):計算機科學與技術(shù)如果用記事本程序打開文本文件“StudentInfo.txt”,就會看到下圖所示的內(nèi)容:69程序的運行結(jié)果如下:16本例中對文件的操作過程①打開文件StudentInfo.txt,如果該文件不存在,則創(chuàng)建一個文件名為StudentInfo.txt的新文件。②將學生信息以文本的形式寫到文件中。③關(guān)閉此文件。④重新打開StudentInfo.txt文件。⑤將文件中的數(shù)據(jù)讀到學生對象中。⑥關(guān)閉此文件。70本例中對文件的操作過程①打開文件StudentInfo.說明

(1)C++提供了3個用于文件輸入/輸出的文件流類,如下所示。 ①ifstream:輸入文件流類,用于文件的輸入。 ②ofstream:輸出文件流類,用于文件的輸出。 ③fstream:輸入/輸出文件流類,用于文件的輸入/輸出。 在使用這些文件流類時,通常要在程序中包含頭文件fstream。例如:

#include<fstream>71說明(1)C++提供了3個用于文件輸入/輸出的文件流類,如(2)文件流類對象的定義和文件的打開①在利用文件流類進行文件操作時,首先要建立流類的對象。例如:

ifstreamfin; ofstreamfout; fstreamfin_out;②可以通過流類對象的構(gòu)造函數(shù)打開文件,例如:

ofstreamfout("StudentInfo.txt");該語句定義了輸出文件流類的對象fout,并通過其構(gòu)造函數(shù)打開了用于輸出的文件StudentInfo.txt。

再例如:

ifstreamfin("StudentInfo.txt");該語句定義了輸入文件流類的對象fin,并通過其構(gòu)造函數(shù)打開了用于輸入的文件StudentInfo.txt。72(2)文件流類對象的定義和文件的打開①在利用文件流類進行文③通過文件流對象的成員函數(shù)open()打開文件調(diào)用該函數(shù)的一般形式為:

文件流對象.open(文件名,打開方式);其中,“文件名”可以包括路徑(如 “D:\\data\\StudentInfo.txt”),如果不指明路徑,則默認為當前目錄下的文件。“打開方式”決定如何打開文件,如表6-1所示。73③通過文件流對象的成員函數(shù)open()打開文件調(diào)用該函數(shù)的表6-1文件的打開方式方式功能ios::app打開一個已存在的文件,以將數(shù)據(jù)添加到文件的尾部。這種方式打開的文件只能用于輸出ios::ate打開一個已存文件,并將文件指針移到文件的尾部ios::binary以二進制的形式打開文件ios::in打開一個文件,進行文件輸入操作ios::out打開一個文件,進行文件輸出操作ios::trunc打開一個文件,如果該文件已存在,則清除文件的內(nèi)容,文件的長度變?yōu)榱?4表6-1文件的打開方式方式功能ios::app打開一個已存●如果用ifstream類來定義一個流對象,則隱含為輸入流,不必再添加ios::in說明;如果用ofstream類來定義一個流對象,則隱含為輸出流,不必再添加ios::out說明。 例如:

ifstreamin; in.open("test.dat");//等同于in.open("test.dat",ios::in); ofstreamout; out.open("test.dat");//等同于out.open("test.dat",ios::out)●當指定“ios::out”方式后,隱含為“ios::trunc”方式,即如果打開的輸出文件已存在,則自動清空該文件的內(nèi)容?!袢绻募蜷_時需要多種打開方式的組合,則應使用“|”(位或操作符)將幾種打開方式組合在一起。例如,可采用以下方式打開一個能夠進行輸入和輸出的二進制文件。

fstreamfin_out; fin_out.open("test.dat",ios::in|ios::out|ios::binary);75●如果用ifstream類來定義一個流對象,則隱含為輸入流④在進行文件打開操作時,應該判斷文件打開是否成功,見下面的語句。

if(fout.fail()) cout<<"Openfilefailture!"<<endl;

fail()函數(shù)是basic_ios類模板(見圖6-1)的成員函數(shù)。在這里,當返回值為true時,說明出現(xiàn)了文件打開錯誤。76④在進行文件打開操作時,應該判斷文件打開是否成功,見下面的(3)文本文件的讀寫●可通過提取運算符“>>”和插入運算符“<<”對文件流對象進行操作,實現(xiàn)文件的讀和寫?!駁etline()函數(shù)

fs.getline(strName,256);//從文件中讀取姓名信息

函數(shù)getline()是basic_istream的成員函數(shù),其函數(shù)聲明是:basic_istream&getline(char_type*_Str,streamsize_Count);

其含義是:從文件流中讀取_Count個字節(jié)到_Str所指的內(nèi)存中,如果還沒有讀取_Count個字節(jié)就遇到回車符'\n',則讀取過程中止。77(3)文本文件的讀寫●可通過提取運算符“>>”和插入運算符“(4)文件的關(guān)閉在對文件的讀寫操作完成后,應關(guān)閉文件。通過關(guān)閉操作,文件流對象與相應的物理文件進行了脫離。如果不進行文件的關(guān)閉,則可能造成文件數(shù)據(jù)的丟失。關(guān)閉文件可使用流類的成員函數(shù)close()完成,例如:fout.close();fin.close();78(4)文件的關(guān)閉在對文件的讀寫操作完成后,應關(guān)閉文件。通過關(guān)6.3利用C++文件流類進行二進制文件的讀寫當進行二進制文件的讀寫時,在打開文件時要使用“ios::binary”來指定以二進制的形式進行文件流的操作。對二進制文件的讀寫可使用C++流類的get()、put()成員函數(shù)或read()、write()成員函數(shù)。這些函數(shù)也可以用于文本文件的讀寫。下面首先通過read()、write()函數(shù)改寫例6-1,實現(xiàn)二進制文件的讀寫,然后介紹get()、put()函數(shù)的使用方法。796.3利用C++文件流類進行二進制文件的讀寫當進行二進制6.3.1利用write()和read()函數(shù)實現(xiàn)二進制文件的讀寫 【例6-2】

二進制文件的讀寫。 本例將學生信息寫入二進制文件,然后再從二進制文件中讀出學生信息并進行顯示。本例在例6-1的代碼基礎(chǔ)上進行修改,主要代碼如下所示。806.3.1利用write()和read()函數(shù)實現(xiàn)二進制……voidCPerson::WriteFile(ofstream&fs){ unsignedcharucStrLength; //計算姓名字符串(包括字符串結(jié)束符)的長度 ucStrLength=strlen(m_strName)+1; //寫入姓名字符串的長度

fs.write((char*)&ucStrLength,sizeof(ucStrLength)); //寫入姓名字符串

fs.write(m_strName,ucStrLength); ucStrLength=strlen(m_strID)+1; //寫入編號字符串的長度

fs.write((char*)&ucStrLength,sizeof(ucStrLength));81……28//寫入編號字符串fs.write(m_strID,ucStrLength);//寫入性別字符fs.write(&m_cSex,sizeof(m_cSex));//寫入出生日期fs.write((char*)&m_Birthday,sizeof(m_Birthday));}82//寫入編號字符串29voidCPerson::ReadFile(ifstream&fs){ unsignedcharucStrLength; //讀入姓名字符串的長度

fs.read((char*)&ucStrLength,sizeof(ucStrLength)); delete[]m_strName; m_strName=newchar[ucStrLength]; //讀入姓名字符串

fs.read(m_strName,ucStrLength);

//讀入編號字符串的長度 fs.read((char*)&ucStrLength,sizeof(ucStrLength)); delete[]m_strID; m_strID=newchar[ucStrLength];

fs.read(m_strID,ucStrLength);//讀入編號字符串 fs.read(&m_cSex,sizeof(m_cSex)); fs.read((char*)&m_Birthday,sizeof(m_Birthday));}83voidCPerson::ReadFile(ifstrea……voidCStudent::WriteFile(ofstream&fs){

CPerson::WriteFile(fs); unsignedcharucStrLength; //計算專業(yè)字符串(包括字符串結(jié)束符)的長度 ucStrLength=strlen(m_strMajor)+1; //寫入專業(yè)字符串長度

fs.write((char*)&ucStrLength,sizeof(ucStrLength)); //寫入專業(yè)字符串

fs.write(m_strMajor,ucStrLength);}84……31voidCStudent::ReadFile(ifstream&fs){

CPerson::ReadFile(fs); unsignedcharucStrLength; //讀入專業(yè)字符串長度

fs.read((char*)&ucStrLength,sizeof(ucStrLength)); delete[]m_strMajor; m_strMajor=newchar[ucStrLength); //讀入專業(yè)字符串

fs.read(m_strMajor,ucStrLength);}85voidCStudent::ReadFile(ifstreunsignedlongCStudent::m_nCount=0;intmain(){ CStudentStudent1("李江","50200900825",'0',1991,3,7,"計算機科學與技術(shù)"); CStudentStudent2("趙梅","50200900826",'1',1991,6,8,"計算機科學與技術(shù)"); CStudentStudent3("武峰","50200900827",'0',1990,5,6,"計算機科學與技術(shù)");

ofstreamfout("StudentInfo.dat",ios::binary);

if(fout.fail()) { cout<<"Openfilefailture!"<<endl; return1; } Student1.WriteFile(fout); Student2.WriteFile(fout); Student3.WriteFile(fout); fout.close();86定義輸出文件流對象fout并通過它打開或創(chuàng)建二進制文件StudentInfo.dat如果文件打開或創(chuàng)建失敗,則退出將學生的信息寫到輸出文件流對象fout中關(guān)閉文件unsignedlongCStudent::m_nCou

ifstreamfin("StudentInfo.dat",ios::binary); if(fin.fail()) { cout<<"Openfilefailture!"<<endl; return1; } CStudentStudent1_1,Student2_1,Student3_1;

Student1_1.ReadFile(fin); Student2_1.ReadFile(fin); Student3_1.ReadFile(fin); fin.close(); Student1_1.DisplayInfo(); cout<<endl; Student2_1.DisplayInfo(); cout<<endl; Student3_1.DisplayInfo(); cout<<endl; return0;}87定義輸入文件流對象fin并通過它打開二進制文件StudentInfo.dat如果文件打開失敗,則退出將輸入流文件對象fin中的數(shù)據(jù)讀到學生對象中關(guān)閉文件輸出學生信息 ifstreamfin("StudentInfo.dat程序的運行結(jié)果如下:姓名:李江編號:50200900825性別:男出生日期:1991,3,7專業(yè):計算機科學與技術(shù)姓名:趙梅編號:50200900826性別:女出生日期:1991,6,8專業(yè):計算機科學與技術(shù)姓名:武峰編號:50200900827性別:男出生日期:1990,5,6專業(yè):計算機科學與技術(shù)如果用記事本程序打開二進制文件“StudentInfo.dat”,就會看到下圖所示的內(nèi)容:88程序的運行結(jié)果如下:35說明(1)在進行二進制文件的讀寫之前,首先要以二進制的形式打開文件,見下面的語句。ofstreamfout("StudentInfo.dat",ios::binary);ifstreamfin("StudentInfo.dat",ios::binary);(2)write()是ostream類的成員函數(shù),其函數(shù)原型如下:ostream&write(constchar*,int);

在進行文件操作時,函數(shù)的第1個參數(shù)表示要寫入文件的數(shù)據(jù)所在的內(nèi)存起始地址,第2個參數(shù)是要寫入文件的字節(jié)數(shù)。(3)read()是istream類的成員函數(shù),其函數(shù)形式如下:

istream&read(char*,int);

在進行文件操作時,函數(shù)的第1個參數(shù)表示從文件中讀入的數(shù)據(jù)所存放的內(nèi)存空間的起始地址,函數(shù)的第2個參數(shù)表示從文件中讀入的字節(jié)數(shù)。89說明(1)在進行二進制文件的讀寫之前,首先要以二進制的形式6.3.2利用get()和put()函數(shù)實現(xiàn)二進制文件的讀寫get()函數(shù)是輸入流類istream的成員函數(shù),可以通過它從文件流對象中讀取數(shù)據(jù),每次讀出一個字節(jié)(字符)。put()函數(shù)是輸出流類ostream的成員函數(shù),可以通過它向文件流對象中寫入數(shù)據(jù),每次寫入一個字節(jié)(字符)。下面給出一個利用get()和put()函數(shù)讀寫二進制文件的例子。906.3.2利用get()和put()函數(shù)實現(xiàn)二進制文件的【例6-3】

將0~9共10個數(shù)寫入二進制文件,然后從該文件中讀取這些數(shù)并顯示。#include<iostream>#include<fstream>usingnamespacestd;intmain(){

ofstreamfout("number.dat",ios::binary); if(fout.fail()) { cout<<"Openfilefailture!"<<endl; return1; }91定義輸出文件流對象fout并通過它打開或創(chuàng)建二進制文件number.dat如果文件打開或創(chuàng)建失敗,則退出【例6-3】將0~9共10個數(shù)寫入二進制文件,然后從該文 for(unsignedcharc=0;c<10;c++)

fout.put(c);

fout.close();

ifstreamfin("number.dat",ios::binary);

if(fin.fail()) { cout<<"Openfilefailture!"<<endl

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論