首页 The C++ IOStreams Library

The C++ IOStreams Library

举报
开通vip

The C++ IOStreams Library The C++ IOStreams Library 1 Introduction The simplest1 way to view a program is as a device for transforming input into output. Programinput output A program is useless unless we have a way of getting information into the program, and a way of getting it ...

The C++ IOStreams Library
The C++ IOStreams Library 1 Introduction The simplest1 way to view a program is as a device for transforming input into output. Programinput output A program is useless unless we have a way of getting information into the program, and a way of getting it out again. Input for a program can be from many sources eg: • User Input. Prompt the user for some information and have them enter it at the command line or in some text field of a GUI. • The Command Line. Read various options/arguments from the command line when the program is invoked. • Environment Vraiables. Most operating systems/shells allow the user to set ”environment variables” eg MOZILLA_HOME=/usr/local/apps/netscape though the precise form varies from OS to OS and shell to shell. A program can gain access to these environment variables through platform dependent library functions. • Files. Read information from a configuration file, import a document for the user to edit, exhibit an image for a user to manipulate etc. • Sensors. Take readings directly from electronic sensors. • Other Programs. Take your input from the output of another program, request another program (still running) to send some data etc. Any one program may use any or all of these sources. Once inside input can be broadly classified as either: • Configuration information that affects the state of the program and how it behaves. • Data to be processed, either automatically or interactively with a user. 1All programs can be considered to be of this form if you sufficiently complicate your description of the input and output. However other models with, say, feedback loops would be a more comfortable fit to interactive GUI programs. 1 Output from a program can go to many places: • The User. Display some information on the command line or in a GUI message box etc. This sort of output is ephemeral unless the user takes some action to capture it. • Files. Store some information in a file. This may contain textual output (eg some program code) or binary output (eg a JPEG image). • Actuators. Send signals to some equipment that causes it to undertake some action (eg switching off a nuclear reactor). • Other Programs. Connect your output to the input of another program, send some data (whilst you are still active) to another program etc. The C++ IOStreams Library, part of the C++ Standard Library, provides a uniform way of handling input from (and output to) any of the above sources (including hardware devices) except for command line arguments and environment variables. Such arguments are delivered to the program by the operating system via the argv parameter of the main function: int main(int argc, char** argv) { // argc contains the number of arguments // argv is an array of character arrays holding the actual arguments ... } The library consists of a set of class templates which can be specialised by the user to handle any sort of input data. They come with ready-made specialisations to handle simple character based input and output either to and from the console or to and from normal files. These notes give an overview of the facilities of the IOStreams library. Another set of notes will discuss command line argument handling. These notes are moderately long for a set of notes but they are short in comparison to the facilities provided — the main reference I used whilst writing them, Josuttis [1], devotes a chapter of 101 pages to the topic! 2 Basic Usage You will already have made much use of cout and cin streams for doing simple input and output to and from the console (command line). For example the following program (the code is in the file examples/ex1.cc) prompts the user to enter some values and then prints out the values entered. #include // This might have to be iostream.h #include int main(int argc, char** argv) { int x; double g; char c; string str; 2 cout << "Enter an integer: "; cin >> x; cout << "Enter a real number: "; cin >> g; cout << "Enter a character: "; cin >> c; cout << "Enter a string: "; cin >> str; cout << "You entered: " << endl; cout << " the integer " << x << endl; cout << " the real number " << g << endl; cout << " the character ’" << c << "’" << endl; cout << " the string \"" << str << "\"" << endl; } Note how the insertion operator << and the extraction operator >> are overloaded to handle many different types. The writer of a new class can also overload these operators so that objects of that class can be written and read in the same way as the builtin types. Note however that these operators do not do validation — if the user enters something unexpected at the prompt you can end up with garbage values for the variable. Also the input stream is not flushed after a read operation. Thus if at the first prompt Enter an integer: the user in fact entered 0.34tykjvo hi there the program would continue without waiting for user input: Enter a real number: Enter a character: Enter a string: You entered: the integer 0 the real number 0.34 the character ’t’ the string "ykjvo" Whilst if the user had entered .90y78hi you would get Enter a real number: Enter a character: Enter a string: You entered: the integer -1073743840 the real number 2.08408 the character ’ the string "" The behaviour of the extraction operator is to skip leading white space then read characters until a character not belonging to the string representation of the data type being input is encountered. Any remaining characters are left in the cin stream to be read by the next use of the extraction operator. 3 You can force the program to skip reading the rest of a line after an extraction operation by using the ignore member function of the cin stream object. This function has a number of forms but the one to use here is (this is not quite the real signature but it shows the intent more clearly) ignore(int count, char delim) The behaviour is to read and discard up to count characters until the character delim is read (this character is also discarded). Thus cin.ignore(1000, ’\n’); would discard up to a 1000 characters or until an end-of-line character was found (whichever came first). You can use functions like this and others if you want to do validated input (that is you don’t trust the user to enter correct data). But a better way to proceed is probably to write a GUI with data-entry fields which can be more easily checked for validity. Use extraction from cin for quick-and-dirty programs or for formatted input from some previously constructed file attached to the cin stream (see later). The other aspect of the above examples is that when reading a string with the extraction operator you cannot include white space in the string. That is if you wanted to read the string ”Hello, World!” you would have to read it in two bits (Hello, and World!) and then put it back together! If you want to read strings with embedded spaces you should use the (global) function getline void getline(istream& in, string str, char delim=’\n’); provided by the string library. This function ignores leading spaces and then reads all characters until the line delimiter or end-of-file is reached. The line delimiter is extracted from the stream but not appended to the string. The default line delimiter character is the newline character ’\n’ but you can pass your own as an optional argument (in which case the newline character is not special and may be appended to the string being read in). Thus a better way to read the string in the above program would be cin.ignore(1000,’\n’); // To flush any new line characters etc -- // see what happens if you don’t use this function cout << "Enter a string: "; getline(cin, str); 3 Behind the Scenes The IOStreams Library is based on the concept of a ”stream”. A stream can represent a file, the console, blocks of memory or hardware devices. The library provides a common set of interfaces (functions) for handling streams. The general picture is as in Figure 1. I/O Device Object State Buffer Translator STREAM >> << Extractor Inserter Figure 1: Stream Structure The user of a stream object rarely has to be concerned with the buffer and translation components which handle conversion of individual bits from the I/O device into the structured data of an object (of either a built 4 in type such as an integer or a user defined type). However the user will need to keep a watch on the state component which notes whether or not an I/O operation has succeeded or failed. The library is built using a fairly complicated set of class templates with the relationships depicted in Figure 2. Figure 2: The Class Structure of the IOStream Library Each of the basic xxxx classes in the diagram is a class template,eg template class basic_ios { .... }; and the standard stream classes are obtained by a series of typedef’s: typedef basic_istream istream; typedef basic_ostream ostream; typedef basic_iostream iostream; typedef basic_istringstream istringstream; typedef basic_ostringstream ostringstream; typedef basic_stringstream stringstream; typedef basic_ifstream ifstream; typedef basic_ofstream ofstream; typedef basic_fstream fstream; The iostream header file provides the standard streams: istream cin; ostream cout; ostream cerr; ostream clog; 5 Note. The above description is based on the current standard. Not all compilers/libraries have caught up with the standard and some are still using an old-style iostream library which was not built according to the above scheme. However the new library (above) was designed so that the instantiated classes have the same interfaces as the old-style and work in the same way. The main exception is that old-style string streams are istrstream, ostrstream and strstream rather than istringstream etc. Currently the GNU C++ Standard library is in a state of transition. It still uses strstream etc and does not base the stream classes on basic xxxx template classes but does provide most of the new style iostream functions and manipulators (as of 2.95, but 2.7 is further behind). 4 The State of Streams Each stream maintains a state that identifies whether an I/O operation was successful or not, and, if not, the reason for the failure. The state of a stream is determined by the settings of a number of flags. These flags are constants of type iostate (a member of the base class ios base). The flags are: • goodbit: If this is set all the other flags are cleared. • eofbit: If this is set then end-of-file was encountered. • failbit: If this is set then the operation was not processed correctly but the stream is generally OK. For example this flag would be set if an integer was to be read but the next character is a letter. • badbit: This is set if the stream has somehow become corrupted or if data is lost. The current state of the flags can be determined by calling various boolean returning member functions that all stream classes possess. • good() – Returns true if the stream is OK (goodbit is set). • eof() – Returns true if end-of-file was encountered (eofbit is set). • fail() – Returns true if an error has occurred (failbit or badbit is set). • bad() – Returns true if a fatal error has occurred (badbit is set). Streams also possess the following more general flag manipulation functions. • You can access all the flags using ios::iostate rdstate(); as in the following example (to be found in examples/rdstateex.cc). #include int main() { int x; cout << "Enter an integer: "; cin >> x; // The state of the stream can be gotten with rdstate. ios::iostate flags = cin.rdstate(); // We can test for which bits are set as follows. // Note the use of the bitwise & operator. 6 if (flags & ios::failbit) cout << "failbit set." << endl; else cout << "failbit not set." << endl; if (flags & ios::badbit) cout << "badbit set." << endl; else cout << "badbit not set." << endl; if (flags & ios::eofbit) cout << "eofbit set." << endl; else cout << "eofbit not set." << endl; // It’s usually easier to test the bits directly: if (cin.good()) cout << "Stream state is good." << endl; else cout << "Stream state is not good." << endl; if (cin.fail()) cout << "Are you sure you entered an integer?" << endl; else cout << "You entered: " << x << endl; } • You can clear all, or selected, flags by using void clear(ios::iostate flags = ios::goodbit); Thus cin.clear() will clear all flags whilst cin.clear(ios::failbit) will clear just the failbit flag. 5 Manipulating Your Stream At the end of many output statements a manipulator is written: cout << "You entered: " << x << endl; The most important manipulators provided by the IOStream library are as follows. • endl – used with a ostream, output a newline and flush the buffer. • ends – used with a ostream, output a null character (\0). • flush – used with a ostream, flushes the output buffer. • ws – used with a istream, reads and discards whitespace. 6 Formatting Your Stream When outputting values to the console or a file (in other words on a istream) you often want to format them in dome way, eg print a floating point number in a field of width 5 with three decimal places etc. 7 The easiest way to do this is to use one of the many formatting manipulators and flags. For example the following program generates 10 random numbers between 0 and 1 (not including 1) and writes them out to a file one to a line with 3 decimal places, a leading zero and a decimal point. (The code can be found in examples/rndnums.cc.) #include // May need to be #include // May need to be #include // Required for rand() -- may need to be #include // For access to time functions (may need to be ) double generateRandNum() { int intRN = rand(); // Each time rand() is called it generates a randomly chosen // integer between 0 and RAND_MAX // This is not the way to generate "good" random numbers between 0 and 1 // but ’twill do for a quick and dirty hack. return double(intRN)/RAND_MAX; } int main() { double rn = 0.0; // Use system time to seed random number generator with different number each // time program is run. srand(time(NULL)); // Standard says that fixed should be a manipulator so that we could write // cout << fixed; // But g++ does not currently support this. cout.setf(ios::fixed); cout << setprecision(3); for (int i=0; i<10; i++) { rn = generateRandNum(); cout << rn << endl; } } The two lines that are doing the formatting in the above are: cout.setf(ios::fixed); cout << setprecision(3); Here ios::fixed is a flag that says the fixed point notation should be used and precision(val) is a manip- ulator that sets val as the precision of floating point values. As it is a manipulator with argument you have to include . Note how the function setf (a member function of all streams) can be used to set a flag. The function for clearing a flag is unsetf. Thus to turn off fixed point notation you would do: cout.unsetf(ios::fixed); There are manipulators and flags which control many different aspects of input and output of character values. The following sections and tables summarise the available manipulators, the flags they set, whether they are to be used for input or output and whether they are currently available with g++. These lists and explanations are not exhaustive (even if they seem exhausting). 8 6.1 Boolean Values Manipulator Affected Flag Effect Input/Output g++ (2.95) boolalpha ios::boolalpha This controls how bool variables are printed. If the flag is set then boolean values are printed as true or false. If the flag is not set then they print as 1 or 0. This manipu- lator sets the flag. Input/Output Neither noboolalpha ios::boolalpha The noboolalpha manipulator un- sets the boolalpha flag. Input/Output Neither As you can see the GNU g++ IOStream Library does not yet provide this feature. If you want to print true or false for the values of a boolean variable you can do something like: cout << (b? "true" : "false") << endl; 6.2 Field Widths, Fill Characters and Output Adjustment Manipulator Affected Flag Effect Input/Output g++ (2.95) setw(val) None Sets the field width to val. This is a minimum value (if the output value is wider than the set width then the width setting is ignored). The set- ting only affects the next formatted output. Input/Output Manipulator setfill(c) None Sets the character c to be the fill character. Output Manipulator left ios::left The manipulator sets the flag. If the flag is set then the value is output left adjusted in the field. Output Flag right ios::right The manipulator sets the flag. If the flag is set then the value is right- adjusted in the field. Output Flag internal ios::internal The manipulator sets the flag. If the flag is set then the value is printed with the sign left-adjusted and the value right-adjusted. Output Flag Note that after any formatted output operation the default field width is restored. The fill character and the adjustment setting remain unchanged until reset. 9 6.3 Positive Sign and Uppercase Letters Manipulator Affected Flag Effect Input/Output g++ (2.95) showpos ios::showpos The manipulator sets the showpos flag. If this flag is set then a posi- tive sign (+) will be printed in front of any positive number (when using decimal notation). Output Flag noshowpos ios::showpos This manipulator clears the showpos flag. Output Flag uppercase ios::uppercase The manipulator sets the flag. If the flag is set then integers using hex- adecimal notation, or floating point numbers using scientific notation, use uppercase for any letters appear- ing in them. Output Flag nouppercase ios::uppercase The manipulator clears the flag. Output Flag 6.4 Number Base Manipulator Affected Flag Effect Input/Output g++ (2.95) dec ios::dec This flag sets the number base for integer number printing and reading to decimal. Input/Output Both hex ios::hex Manipulator sets the hex flag. Which causes input and output of integers to use hexadecimal nota- tion. Input/Output Both oct ios::oct Manipulator sets the oct flag. Which causes input and output of integers to use octal notation. Input/Output Both If none of these flags is set then a decimal base is used, if more than one flag is set then a decimal base is used. During input if no flag is set then the base is determined by the leading characters. A number starting with 0x or 0X is read as a hexadecimal number, whilst if it starts with a leading zero it is read as an octal number. Using the manipulators is easier than using the flags. To read/write binary numbers use the bitset class from the Standard Template Library. 6.5 Floating Point Representation Manipulator Affected Flag Effect Input/Output g++ (2.95) fixed ios::fixed The manipulator sets the flag. If flag is set use fixed point decimal nota- tion for floating point numbers. Output Flag scientific ios::scientific The manipulator sets the flag. If the flag is set then use scientific notation for floating point numbers. Output Flag showpoint ios::showpoint The manipulator sets the flag. If the flag is set always write a decimal. Output Flag noshowpoint ios::showpoint The manipulator clears the flag. Output Flag setprecision(val) None Sets the precision of floating point printing to val. Output Manipulator 10 As you can see there are no manipulators for clearing the fixed or scientific flags. Use unsetf for this task. Output streams also have a precision() member function which returns the current precision. 6.6 Miscellaneous Manipulator Affected Flag Effect Input/Output g++ (2.95) endl None Output a newline character and flush the stream. Output Manipulator ends None Output a null character. Output Manipulator flush None Flush a stream. Output Manipulator 7 Stream Member
本文档为【The C++ IOStreams Library】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_725026
暂无简介~
格式:pdf
大小:141KB
软件:PDF阅读器
页数:15
分类:互联网
上传时间:2010-03-30
浏览量:23