C++Primer Plus筆記——第十七章 輸入、輸出和檔案總結及程式清單
目錄
本章小結
流是進出程式的位元組流。緩衝區足記憶體中的臨時儲存區域,是程式與檔案或其他I/O裝置之間的橋樑。 資訊在緩衝區和檔案之間傳輸時,將使用裝置(如磁碟驅動器)處理效率最高的尺寸以大塊資料的方式進行傳輸。資訊在緩衝區和程式之間傳輸時,是逐位元組傳輸的,這種方式對於程式中的處理操作更為方便。 C++通過將一個被緩衝流同程式及輸入源相連來處理輸入。同樣,C++也通過將一個被緩衝流同程式及其輸出目標相連來處理輸出。iostream和fstream檔案構成了 I/O類庫,該類庫定義了大量用於管理流的類。 包含了 iostream檔案的C++程式將自動開啟8個流,並使用8個物件管理它們。cin物件管理標準輸入流, 後者預設與標準輸入裝置(通常為鍵盤)相連:cout物件管理標準輸出流,後名預設與標準輸出裝置(通常為M示器)相連;cerr和clog物件管理與標準錯誤裝置(通常為顯示器)相連的未被緩衝的流和被緩衝的流。這4個物件有都有用於寬字元的副本,它們是wcin、wcout、wcerr和wclog。
I/O類庫提供了大量有用的方法。istream類定義了多個版本的抽取運算子(>>),用於識別所有基本的 C++型別,並將字元輸入轉換為這些型別。get( )方法族和getline()方法為單字元輸入和字串輸入提供了進一步的支援。同樣,ostream類定義了多個版木的插入運算子(<<),用於識別所有的C++基本型別,並將它們轉換為相應的字元輸出。put()方法對單字元輸出提供進一步的支援。wistream和wostrcam類對寬字元提供了類似的支援。
使用ios_base類方法以及檔案iostream和iomanip中定義的控制符(可與插入運算子拼接的函式),可以控制程式如何格式化輸出。這些方法和控制符使得能夠控制計數系統、欄位寬度、小數位數、顯示浮點變數時採用的計數系統以及其他元素.
fstream檔案提供了將iostream方法擴充套件到檔案I/O的類定義。ifstream類是從istream類派生而來的。 通過將ifstream物件與檔案關聯起來,可以使用所有的istream方法來讀取檔案。同樣,通過將ofstream物件與檔案關聯起來,可以使用ostream方法來寫檔案:通過將fstream物件與檔案關聯起來,可以將輸入和 輸出方法用於檔案。
要將檔案與流關聯起來,可以在初始化檔案流物件時提供檔名,也可以先建立一個檔案流物件,然後用open()方法將這個流與檔案關聯起來。close()方法終止流與檔案之間的連線。類建構函式和open() 方法接受可選的第一個引數,該引數提供檔案模式。檔案模式決定檔案是否被讀和/或寫、開啟檔案以便寫 入時是否截短檔案、試圖開啟不存在的檔案時是否會導致錯誤、是使用二進位制模式還是文字模式等。
文字檔案以字元格式儲存所有的資訊,例如,數字值將被轉換為字元表示。常規的插入和抽取運算子以及get()和getline()都支援這種模式。二進位制檔案使用計算機內部使用的二進位制表示來儲存資訊。與文字檔案相比,二進位制檔案儲存資料(尤其是浮點值)更為精確、簡潔,但可移植性較差。read()和write()方法都支援二進位制輸入和輸出。
seekg()和seekp()函式提供對檔案的隨機存取。這些類方法使得能夠將檔案指標放置到相對於檔案開頭、檔案尾和當前位置的某個位置。tellg()和tellp()法報摶當前的檔案位置。
sstream標頭檔案定義了 istringstream和ostringstream類,這擇類使得能夠使用istream和ostream方法來抽取字串中的資訊。並對要放入到字串中的資訊進行格式化。
程式清單
使用cout進行輸出
17.1 write.cpp
演示write()函式
// write.cpp -- using cout.write!)
#include <iostream>
#include <cstring> // or else string.h
int main()
{
using std::cout;
using std::endl;
const char * statel = "Florida";
const char * state2 = "Kansas";
const char * state3 = "Euphoria";
int len = std::strlen(state2);
cout << "Increasing loop index:\n";
int i;
for (i = 1; i <= len; i++)
{
cout.write(state2, i);
cout << endl;
}
// concatenate output
cout << "Decreasing loop index:\n";
for (i = len; i > 0; i--)
cout.write(state2, i) << endl;
// exceed string length
cout << "Exceeding string length:\n";
cout.write(state2, len + 5) << endl;
return 0;
}
17.2 defaults.cpp
演示預設輸出
// defaults.cpp -- cout default formats
#include <iostream>
int main()
{
using std::cout;
cout << "12345678901234567890\n";
char ch = 'K';
int t = 273;
cout << ch << "An";
cout << t << " An";
cout << -t << "An";
double fl = 1.200;
cout << fl << ":\n";
cout << (fl + 1.0 / 9.0) << "An";
double f2 = 1.67E2;
cout << f2 << "An";
f2 += 1.0 / 9.0;
cout << f2 << "An";
cout << (f2 * 1.0e4) << "An";
double f3 = 2.3e-4;
cout << f3 << "An";
cout << f3 / 10 << "An";
return 0;
}
17.3 manip.cpp
使用控制符
// manip.cpp -- using format manipulators
#include <iostream>
int main()
{
using namespace std;
cout << "Enter an integer: ";
int n;
cin >> n;
cout << "n n*n\n";
cout << n << " " << n * n << " (decimal)\n";
// set to hex mode
cout << hex;
cout << n << " ";
cout << n * n << " (hexadecimal)\n";
// set to octal mode
cout << oct << n << " " << n * n << " (octal)\n";
// alternative way to call a manipulator dec < cout);
cout << n << " " << n * n << " (decimal)\n";
return 0;
}
17.4 width.cpp
演示用於調整欄位寬度的width()函式
// width.cpp -- using the width method
#include <iostream>
int main()
{
using std::cout;
int w = cout.width(30);
cout << "default field width = " << w << ":\n";
cout.width(5);
cout << "N" << ":";
cout.width(8);
cout << "N * N" << ":\n";
for (long i = 1; i <= 100; i *= 10)
{
cout.width(5);
cout << i << ":";
cout.width(8);
cout << i * i << ":\n";
}
return 0;
}
17.5 fill.cpp
演示用於填充字元的fill()函式
// fill.cpp -- changing fill character for fields
#include <iostream>
int main()
{
using std::cout;
cout.fill('*');
const char * staff[2] = { "Waldo Whipsnade", "Wilmarie Wooper" };
long bonus[2] = { 900, 1350 };
for (int i = 0; i < 2; i++)
{
cout << staff[i] << ": $";
cout.width(7);
cout << bonus[i] << "\n";
}
return 0;
}
17.6 precise.cpp
演示用於設定浮點數顯示精度的precision()函式
//precise.cpp -- setting the precision
#include <iostream>
int main()
{
using std::cout;
float pricel = 20.40;
float price2 = 1.9 + 8.0 / 9.0;
cout << "V'Furry Friends\" is S" << pricel << "!\n ";
cout << "\"Fiery Fiends\" is $" << price2 << "!\n";
cout.precision(2);
cout << "\"Furry Friends\" is $" << pricel << "!\n ";
cout << "\"Fiery Fiends\" is $" << price2 << "!\n";
return 0;
}
17.7 showpt.cpp
設定小數點的方法
// showpt.cpp -- setting the precision, showing trailing point
#include <iostream>
int main()
{
using std::cout;
using std::ios_base;
float pricel = 20.40;
float price2 = 1.9 + 8.0 / 9.0;
cout.setf(ios_base::showpoint);
cout << "\"Furry Friends\" is $" << pricel << "!\n";
cout << "\"Fiery Fiends\" is $" << price2 << "!\n";
cout.precision(2);
cout << "\MFurry Friends\" is $" << pricel << "!\n";
cout << "\"Fiery Fiends\" is $" << price2 << "!\n";
return 0;
}
17.8 setf.cpp
設定小數點的格式常量
//setf.cpp -- using setf() to control formatting
#include <iostream>
int main()
{
using namespace std;
int temperature = 63;
cout << "Today's water temperature:";
cout.setf(ios_base::showpos); // show plus sign
cout << temperature << endl;
cout << "For our programming friends, that's\n";
cout << std::hex << temperature << endl; // use hex
cout.setf(ios_base::uppercase); // use uppercase in hex
cout.setf(ios_base::showbase); // use OX prefix for hex
cout << "or\n";
cout << temperature << endl;
cout << "How " << true << "! oops -- How ";
cout.setf(ios_base::boolalpha);
cout << true << "!\n";
return 0;
}
17.9 setf2.cpp
使用兩個引數設定小數點
// setf2.cpp -- using setf() with 2 arguments to control formatting
#include <iostream>
#include <cmath>
int main()
{
using namespace std;
// use left justification, show the plus sign, show trailing
// zeros, with a precision of 3
cout.setf(ios_base::left, ios_base::adjustfield);
cout.setf(ios_base::showpos);
cout.setf(ios_base::showpoint);
cout.precision(3);
// use e-notation and save old format setting
ios_base::fmtflags old = cout.setf(ios_base::scientific, ios_base::floatfield);
cout << "Left Justification:\n";
long n;
for (n = 1; n <= 41; n += 10)
{
cout.width(4);
cout << n << "|";
cout.width(12);
cout << sqrt(double(n)) << "|\n";
// change to internal justification
cout.setf(ios_base::internal, ios_base::adjustfield);
// restore default floating-point display style
cout.setf(old, ios_base::floatfield);
cout << "Internal Justification:\n"; for (n = 1; n <= 41; n += 10)
{
cout.width(4); cout << n << cout.width(12);
cout << sqrt(double(n)) << "|\n";
}
// use right justification, fixed notation
cout.setf(ios_base::right, ios_base::adjustfield);
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "Right Justification:\n";
for (n = 1; n <= 41; n += 10)
{
cout.width(4);
cout << n << " |";
cout.width(12);
cout << sqrt(double(n)) << "|\n";
}
return 0;
}
17.10 iomanip.cpp
使用標頭檔案iomanip
// iomanip.cpp -- using manipulators from iomanip
// some systems require explicitly linking the math library
#include <iostream>
#include <iomanip>
#include <cmath>
int main()
{
using namespace std;
// use new standard manipulators
cout << fixed << right;
// use iomanip manipulators
cout << setw(6) << "N" << setw(14) << "square root" << setw(15) << "fourth root\n";
double root;
for (int n = 10; n <= 100; n += 10)
{
root * sqrt(double(n));
cout << setw(6) << setfill('.') << n << setfill(' ')
<< setw(12) << setprecision(3) << root
<< setw(14) << setprecision(4) << sqrt(root) << endl;
}
return 0;
}
使用cin進行輸入
17.11 check_it.cpp
如何檢查輸入
// check_it.cpp -- checking for valid input
#include <iostream>
int main()
{
using namespace std;
cout << "Enter numbers: ";
int sum = 0;
int input;
while (cin >> input)
{
sum += input;
}
cout << "Last value entered = " << input << endl;
cout << "Sum = " << sum << endl;
return 0;
}
17.12 cinexcp.cpp
捕獲異常
// cinexcp.cpp -- having cin throw an exception
#include <iostream>
#include <exception>
int main()
{
using namespace std;
// have failbit cause an exception to be thrown
cin.exceptions(ios_base::failbit);
cout << "Enter numbers: ";
int sum = 0;
int input;
try {
while (cin >> input)
{
sum += input;
}
}
catch (ios_base::failure & bf)
{
cout << bf.what() << endl;
cout << "0! the horror!\n";
}
cout << "Last value entered = " << input << endl;
cout << "Sum = " << sum << endl;
return 0;
}
17.13 get_fun.cpp
使用字串輸入函式
// get_fun.cpp -- using get() and getline()
#include <iostream>
const int Limit = 255;
int main()
{
using std::cout;
using std::cin;
using std::endl;
char input[Limit];
cout << "Enter a string for getlineO processing:\n";
cin.getline(input, Limit, '#');
cout << "Here is your input:\n";
cout << input << "\nDone with phase 1\n";
char ch;
cin.get(ch);
cout << "The next input character is " << ch << endl;
if (ch != '\n')
cin.ignore(Limit, '\n'); // discard rest of line
cout << "Enter a string for get() processing:\n";
cin.get(input, Limit, '#');
cout << "Here is your input:\n";
cout << input << "\nDone with phase 2\n";
cin.get(ch);
cout << "The next input character is " << ch << endl;
return 0;
}
17.14 peeker.cpp
使用其他輸入函式
// peeker.cpp -- some istream methods
#include <iostream>
int main()
{
using std::cout;
using std::cin;
using std::endl;
// read and echo input up to a # character
char ch;
while (cin.get(ch))// terminates on EOF
{
if (ch != '#')
cout << ch;
else
{
cin.putback(ch); // reinsert character
break;
}
}
if (!cin.eof())
{
cin.get(ch);
cout << endl << ch << " is next input character.\n";
}
else
{
cout << "End of file reached.\n";
std::exit(0);
}
while (cin.peek() != '#') // look ahead
{
cin.get(ch);
cout << ch;
}
if (!cin.eof())
{
cin.get(ch);
cout << endl << ch << " is next input character.\n";
}
else
cout << "End of file reached.\n";
return 0;
}
17.15 truncate.cpp
使用其他輸入函式
// truncate.cpp -- using get() co truncate input line, if necessary
#include <iostream>
const int SLEN = 10;
inline void eatline() { while (std::cin.get() != '\n') continue; }
int main()
{
using std::cin;
using std::cout;
using std::endl;
char name[SLEN];
char title[SLEN];
cout << "Enter your name: ";
cin.get(name, SLEN);
if (cin.peek() != '\n')
cout << "Sorry, we only have enough room for " << name << endl;
eatline();
cout << "Dear " << name << ", enter your title: \n";
cin.get(title, SLEN); if (cin.peek() != '\n')
cout << "We were forced to truncate your title.\n";
eatline();
cout << " Name: " << name << "\nTitle: " << title << endl;
return 0;
}
檔案的輸入和輸出
17.16 fileio.cpp
簡單的檔案輸入輸出
//fileio.cpp -- saving to a file
#include <iostream> // not needed for many systems
#include <fstream>
#include <string>
int main()
{
using namespace std;
string filename;
cout << "Enter name for new file: ";
cin >> filename;
// create output stream object for new file and call it fout
ofstream fout(filename.c_str());
fout << "For your eyes only!\n"; // write to file
cout << "Enter your secret number: ";// write to screen
float secret; cin >> secret;
fout << "Your secret number is " << secret << endl;
fout.close(); // close file
// create input stream object for new file and call it fin
ifstream fin(filename.c_str());
cout << "Here are the contents of " << filename << ":\n"; char ch;
while (fin.get(ch)) // read character from file and
cout << ch; // write it to screen
cout << "Done\n";
fin.close();
return 0;
}
17.17 count.cpp
命令列處理技術
//count.cpp -- counting characters in alist of files
#include <iostream>
#include <fstream>
#include <cstdlib> // for exit()
int main(int argc, char * argv[])
{
using namespace std;
if (argc == 1) // quit if no arguments
{
cerr << "Usage: " << argv[0] << " filenameIsl\n";
exit(EXIT_FAILURE);
}
ifstream fin; // open stream
long count;
long total = 0;
char ch;
for (int file = 1; file < argc; file++)
{
fin.open(argv[file]); // connect stream to argv[file]
if (!fin.is_open())
{
cerr << "Could not open " << argv[file] << endl;
fin.clear();
continue;
}
count = 0;
while (fin.get(ch))
count++;
cout << count << " characters in " << argv[file] << endl;
total += count;
fin.clear();// needed for some implementations
fin.close();// disconnect file
}
cout << total << " characters in all files\n";
return 0;
}
17.18 append.cpp
追加檔案
//append.cpp -- appending information to a file
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
// (for exit()
const char * file = "guests.txt";
int main()
{
using namespace std;
char ch;
// show initial contents
ifstream fin;
fin.open(file);
if (fin.is_open())
{
cout << "Here are the current contents of the " << file << " file : \n";
while (fin.get(ch))
cout << ch;
fin.close();
}
// add new names
ofstream fout(file, ios::out | ios::app);
if (!fout.is_open())
{
cerr << "Can't open " << file << " file for output.\n";
exit(EXIT_FAILURE);
}
cout << "Enter guest names (enter a blank line to quit):\n ";
string name;
while (getline(cin, name) && name.size() > 0)
{
fout << name << endl;
}
fout.close();
// show revised file
fin.clear(); // not necessary for some compilers
fin.open(file);
if (fin.is_open())
{
cout << "Here are the new contents of the " << file << " file:\n";
while (fin.get(ch))
cout << ch;
fin.close();
}
cout << "Done.\n";
return 0;
}
17.19 binary.cpp
二進位制檔案
// binary.cpp -- binary file I/O
#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // for exit()
inline void eatline()
{
while (std::cin.get() != '\n')
continue;
}
struct planet
{
char name[20]; // name of planet
double population; // its population
double g; // its acceleration of gravity
};
const char * file = "planets.dat";
int main()
{
using namespace std;
planet pl;
cout << fixed << right;
// show initial contents
ifstream fin;
fin.open(file, ios_base::in | ios_base::binary); // binary file
//NOTE: some systems don't accept the ios_base::binary mode
if (fin.is_open())
{
cout << "Here are the current contents of the " << file << " file:\n";
while (fin.read((char *)&pl, sizeof pl))
{
cout << setw(20) << pl.name << ": "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
fin.close();
}
// add new data
ofstream fout(file, ios_base::out | ios_base::app | ios_base::binary); //NOTE: some systems don't accept the ios::binary mode
if (!fout.is_open())
{
cerr << "Can't open " << file << " file for output:\n";
exit(EXIT_FAILURE);
}
cout << "Enter planet name (enter a blank line to quit):\n";
cin.get(pl.name, 20);
while (pl.name[0] != '\0')
{
eatline();
cout << "Enter planetary population: ";
cin >> pl.population;
cout << "Enter planet's acceleration of gravity: ";
cin >> pl.g;
eatline();
cout.write((char *)&pl, sizeof pl);
cout << "Enter planet name (enter a blank line to quit):\n";
cin.get(pl.name, 20);
}
fout.close();
// show revised file
fin.clear(); // not required for some implementations, but won't hurt
fin.open(file, ios_base::in | ios_base::binary);
if (fin.is_open())
{
cout << "Here are the new contents of the " << file << " file:\n";
while (fin.read((char *)&pl, sizeof pl))
{
cout << setw(20) << pl.name << ": "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
fin.close();
}
cout << "Done.\n";
return 0;
}
17.20 random.cpp
隨機存取
// random.cpp -- random access to a binary file
#include <iostream> // not required by most systems
#include <fstream>
#include <iomanip>
#include <cstdlib> // for exit()
const int LIM = 20;
struct planet
{
char name[LIM];// name of planet
double population;// its population
double g;// its acceleration of gravity
};
const char * file = "planets.dat"; // ASSUMED TO EXIST (binary.cpp example)
inline void eatline() { while (std::cin.get() != '\n') continue; }
int main()
{
using namespace std;
planet pl;
cout << fixed;
// show initial contents
fstream finout; // read and write streams
finout.open(file, ios_base::in | ios_base::out | ios_base::binary);
//NOTE: Some Unix systems require omitting - ios::binary
int ct = 0;
if (finout.is_open())
{
finout.seekg(0);// go to beginning
cout << "Here are tRe current contents of the " << file << " file: \n";
while (finout.read((char *)&pl, sizeof pl))
{
cout << ct++ << ": " << setw(LIM) << pl.name << ": "
<< setprecision(0) << setw(-12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
if (finout.eof())
finout.clear(); // clear eof flag
else
{
cerr << "Error in reading " << file << ".\n";
exit(EXIT_FAILURE);
}
}
else
{
cerr << file << " could not be opened -- bye.\n";
exit(EXIT_FAILURE);
}
// change a record
cout << "Enter the record number you wish to change: ";
long rec;
cin >> rec;
eatline(); // get rid of newline
if (rec < 0 || rec >= ct)
{
cerr << "Invalid record number -- bye\n";
exit(EXIT_FAILURE);
}
streampos place = rec * sizeof pl; // convert to streampos type
finout.seekg(place); // random access
if (finout.fail())
{
cerr << "Error on attempted seek\n";
exit(EXIT_FAILURE);
}
finout.read((char *)&pl, sizeof pl);
cout << "Your selection:\n";
cout << rec << ": " << setw(LIM) << pl.name << ": "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
// clear eof flag
if (finout.eof())
finout.clear();
cout << "Enter planet name: ";
cin.get(pl.name, LIM);
eatline();
cout << "Enter planetary population: ";
cin >> pl.population;
cout << "Enter planet's acceleration of gravity: ";
cin >> pl.g;
finout.seekp(place); // go back
finout.write((char *)&pl, sizeof pl) << flush;
if (finout.fail())
{
cerr << "Error on attempted write\n";
exit(EXIT_FAILURE);
}
// show revised file ct = 0;
finout.seekg(0); // go to beginning of file
cout << "Here are the new contents of the " << file << "file:\n";
while (finout.read((char *)&pl, sizeof pl))
{
cout << ct++ << ": " << setw(LIM) << pl.name << ": "
<< setprecision(0) << setw(12) << pl.population
<< setprecision(2) << setw(6) << pl.g << endl;
}
finout.close();
cout << "Done.\n";
return 0;
}
核心格式化
17.21 strout.cpp
// strout.cpp -- incore formatting (output)
#include <iostream>
#include <sstream>
#include <string>
int main()
{
using namespace std;
ostringstream outstr; // manages a string
string hdisk;
cout << "What's the name of your hard disk? ";
getline(cin, hdisk);
int cap;
cout << "What's its capacity in GB? ";
cin >> cap;
// write formatted information to string stream
outstr << "The hard disk " << hdisk << " has a capacity of " << cap << " gigabytes.\n";
string result = outstr.str(); // save result
cout << result; // show contents
return 0;
}
17.22 strin.cpp
// strin.cpp -- formatted reading from a char array
#include <iostream>
#include <sstream>
#include <string>
int main()
{
using namespace std;
string lit = "t was a dark and stormy day, and the full moon glowed brilliantly. ";
istringstream instr(lit); // use buf for input
string word;
while (instr >> word)// read a word a time
cout << word << endl;
return 0;
}