1. 程式人生 > >C++Primer Plus筆記——第十七章 輸入、輸出和檔案總結及程式清單

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;
}