目录
17.1 write.cpp 17.2 defaults.cpp 17.3 manip.cpp 17.4 width.cpp 17.5 fill.cpp
17.6 precise.cpp 17.7 showpt.cpp 17.8 setf.cpp 17.9 setf2.cpp 17.10 iomanip.cpp
17.11 check_it.cpp 17.12 cinexcp.cpp 17.13 get_fun.cpp 17.14 peeker.cpp 17.15 truncate.cpp
17.16 fileio.cpp 17.17 count.cpp 17.18 append.cpp 17.19 binary.cpp 17.20 random.cpp
17.21 strout.cpp 17.22 strin.cpp
本章小结
流是进出程序的字节流。缓冲区足内存中的临时存储区域,是程序与文件或其他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;
}