A Complete Guide to Programming in C++ part 42 doc

10 292 0
A Complete Guide to Programming in C++ part 42 doc

Đang tải... (xem toàn văn)

Thông tin tài liệu

CLOSING FILES ■ 389 ᮀ Motivation After you have completed file manipulation, the file should always be closed for the fol- lowing reasons: ■ data may be lost, if for some reason the program is not terminated correctly ■ there is a limit to the number of files that a program can open simultaneously. A program that terminates correctly will automatically close any open files before exit- ing. A file stream destructor will also close a file referenced by a stream. However, if the file is no longer in use before this point, you should close the file explicitly. ᮀ Methods close() and is_open() Each of the file stream classes contains a definition of a void type method called close(), which is used to close the file belonging to the stream. Example: myfile.close(); However, the file stream continues to exist. It is therefore possible to use the stream to open and manipulate another file. If you are not sure whether a file stream is currently accessing a file, you can always perform a test using the is_open() method . In the case of the myfile file stream, the test is as follows: Example: if( myfile.is_open() ) { /* . . . */ } // File is open ᮀ The exit() Function Open files are also closed when you call the global function exit(). The actual reason for using this function is to terminate a program in an orderly manner and return an error code to the calling process. Prototype: void exit( int status ); The calling process, to which the status error code is passed for evaluation, will often be the command interpreter—a Unix shell, for example. Successful program execu- tion normally produces the error code 0. The statement return n; is thus equivalent to the statement exit(n); when used in the main() function. The program on the opposite page copies a file stated in the command line. If the user forgets to state a second (target) file, the source file is copied to standard output. In this case, the source file will need to be a text file. 390 ■ CHAPTER 18 FUNDAMENTALS OF FILE INPUT AND OUTPUT // Pizza_W.cpp // Demonstrating output of records block by block. // #include <iostream> #include <fstream> using namespace std; char header[] = " * * * P I Z Z A P R O N T O * * *\n\n"; // Record structure: struct Pizza { char name[32]; float price; }; const int MAXCNT = 10; Pizza pizzaMenu[MAXCNT] = { { "Pepperoni", 9.90F }, { "White Pizza", 15.90F }, { "Ham Pizza", 12.50F }, { "Calzone", 14.90F } }; int cnt = 4; char pizzaFile[256] = "pizza.fle"; int main() // To write records. { cout << header << endl; // To write data into the file: int exitCode = 0; ofstream outFile( pizzaFile, ios::out|ios::binary ); if( !outFile) { cerr << "Error opening the file!" << endl; exitCode = 1; } else { for( int i = 0; i < cnt; ++i) if( !outFile.write( (char*)&pizzaMenu[i], sizeof(Pizza)) ) { cerr << "Error writing!" << endl; exitCode = 2; } } if( exitCode == 0) cout << "\nData has been added to file " << pizzaFile << "\n" << endl; return exitCode; } ■ READING AND WRITING BLOCKS Sample program READING AND WRITING BLOCKS ■ 391 The file stream classes can use all the public operations defined in their base classes. This means you can write formatted or unformatted data to a file or read that data from the file block by block or character by character. ᮀ Formatted and Unformatted Input and Output The previous sample programs illustrated how to use the methods get(), getline(), and put() to read or write data from or to text files. Formatted input and output of numerical values, for example, requires the >> and << operators and appropriate manip- ulators or formatting methods. Example: double price = 12.34; ofstream textFile("Test.txt"); textFile << "Price: " << price << "Dollar" << endl; The file Test.txt will contain a line of text, such as "Price " that exactly matches the screen output. Converting binary data to legible text is not practicable if you are dealing with large amounts of data. It makes sense to write the data for a series of measurements to a binary file in the order in which they occur in the program. To do so, you simply open the file in binary mode and write the data to the file, or read it from the file, block by block. ᮀ Transferring Data Blocks The ostream method write() transfers given number of bytes from main memory to a file. Prototype: ostream& write( const char *buf, int n); Since write() returns a reference to the stream, you can check to ensure that the write operation was successful. Example: if( ! fileStream.write("An example ", 2) ) cerr << "Error in writing!" << endl; A warning is issued if an error occurs while writing the characters "An". You can use the read() method to read data blocks from the file. The method transfers a data block from a file to a program buffer. Prototype: istream& read( char *buf, int n); The methods read() and write() are often used for files with fixed length records. The block that needs to be transferred can contain one or more records. The buffer in main memory is either a structure variable or an array with elements belonging to the structure type. You need to cast the address of this memory area to (char *) as shown in the example opposite. 392 ■ CHAPTER 18 FUNDAMENTALS OF FILE INPUT AND OUTPUT // Class Account with methods read() and write() // class Account { private: string name; // Account holder unsigned long nr; // Account number double balance; // Balance of account public: . . . // Constructors, destructor, // access methods, ostream& Account::write(ostream& os) const; istream& Account::read(istream& is) }; // write() outputs an account into the given stream os. // Returns: The given stream. ostream& Account::write(ostream& os) const { os << name << '\0'; // To write a string os.write((char*)&nr, sizeof(nr) ); os.write((char*)&balance, sizeof(balance) ); return os; } // read() is the opposite function of write(). // read() inputs an account from the stream is // and writes it into the members of the current object istream& Account::read(istream& is) { getline( is, name, '\0'); // Read a string is.read( (char*)&nr, sizeof(nr) ); is.read( (char*)&balance, sizeof(balance)); return is; } ■ OBJECT PERSISTENCE Class Account Implementing methods read() and write() OBJECT PERSISTENCE ■ 393 ᮀ Storing Objects Objects are created during program runtime and cleaned up before the program termi- nates. To avoid this volatility, you can make an object persistent, that is, you can store the object in a file. However, you must ensure that the object can be reconstructed, as it was, when read. This means dealing with the following issues: ■ Objects can contain other objects. You will generally not know how to store a member object. ■ Objects can contain references to other objects. However, it does not make sense to store pointer values in a file, as the memory addresses will change each time you re-launch the program. For example, the class Account on the opposite page contains the member object name, which is a string type. As string type objects are used to handle variable length strings, the object just contains a reference to the string. It therefore makes no sense to save the memory content of size sizeof(name) occupied by the object name in a file. Instead, you should write the string itself to a file. One possible solution to this issue is to store the data to allow them to be passed to a constructor for the class when read. Another solution involves providing methods to allow the objects to write their own data members to files or read them from files. This technique is normally preferable since the class can now handle data storage itself, allow- ing it to write internal status data while simultaneously preventing external access to that data. ᮀ Storing Account Class Objects The opposite page shows the Account class, with which you are already familiar. File input and output methods have been added to the class. A file stream that references a file opened in binary mode is passed as an argument to the methods read() and write(). The return value is the stream in both cases, so the status can be queried when the function is called. Example: if( ! anAccount.write( outFile) ) cerr << "Error in writing!" << endl; When you read an account, you can simultaneously create an empty object that the read() method can access. Example: if( ! anAccount.read( inFile) ) cerr << "Error in reading!" << endl; The member object name is saved as a C string, that is, as a string terminated by the null character, '\0'. The << operator and the function getline() are available for this task. exercises 394 ■ CHAPTER 18 FUNDAMENTALS OF FILE INPUT AND OUTPUT fcopy file1 file2 A file, file1, is copied to file2. If file2 already exists, it is overwritten. fcopy file1 A file, file1, is copied to standard output, that is, to the screen if standard output has not been redirected. fcopy For calls without arguments, the source and destination files are entered in a user dialog. If is is a file stream that references a file opened for reading, the following call Example: char buf[1024]; is.read(buf, 1024); transfers the next 1024 bytes from file to the buffer buf. Provided that no error occurs, no less than 1024 bytes will be copied unless end-of-file is reached. In this case the fail and eof bits are set.The last block of bytes to be read also has to be written to the destination file.The method gcount() returns the number of bytes transferred by the last read operation. Example: int nread = is.gcount(); // Number of bytes // in last read op. ■ EXERCISES For exercise 1 Possible calls to the program fcopy: More details on the istream class method read() EXERCISES ■ 395 Exercise 1 The sample program fcopy1, which copies a file to the screen or to a second file, was introduced in this chapter.Write a program named fcopy to enhance fcopy1 as follows: ■ If the program is launched without any arguments, it does not issue an error message and terminate but requests user input for the names of the source and target files. If an empty string is given as the name of the tar- get file, that is, the Return key is pressed, the source file is displayed on screen. ■ If the command line or the user dialog contains valid source and target file names, a binary copy operation is performed. ■ Copy the data block by block with the read() and write() methods. The default block size is 1024 bytes. ■ The copy() function returns false if an error occurs while copying and true in all other cases. Also refer to the notes on the opposite page. Exercise 2 a. Modify the sample program Pizza_w.cpp in this chapter to allow the user to add new pizza records to the four standard pizzas and store these records on file. b. Then write a program called Pizza_r.cpp, which displays the pizza menu, that is, outputs the contents of the pizza file. Exercise 3 Test the methods read() and write() in the Account class.To do so, write a program called Account_rw.cpp that ■ initializes an array with account objects and stores the array in a file ■ reads the contents of the file to a second array and displays the accounts in that array to allow you to check them. Use binary mode for read or write access to the file. 396 ■ CHAPTER 18 FUNDAMENTALS OF FILE INPUT AND OUTPUT New data members: string filename; // File name bool dirty; // true, if data is not // stored yet. New methods: const string& getFilename() const; bool setFilename( const string& fn); bool isDirty() const; bool load(); // Read data from the file bool save(); // Save data. bool saveAs(); // Save data as * * * * * Telephone List * * * * * S = Show all entries F = Find a telephone number A = Append an entry D = Delete an entry O = Open a file W = Save in the file U = Save as Q = Quit the program Your choice: For Exercise 4 New members of class TelList Extended menu of the application program EXERCISES ■ 397 Exercise 4 The program TelList, which was written as an exercise for Chapter 16, needs to be modified to allow telephone lists to be saved in a file. To allow this, first add the data members and methods detailed on the opposite page to TelList.The string filename is used to store the name of the file in use.The dirty flag is raised to indicate that the phone list has been changed but not saved.You will need to modify the existing methods append() and erase()to provide this functionality. The strings in the phone list must be saved as C strings in a binary file, allowing for entries that contain several lines. Add the following items to the application program menu: O = Open a file Read a phone list previously stored in a file. W = Save Save the current phone list in a file. U = Save as . . . Save the current phone list in a new file. Choosing one of these menu items calls one of the following methods as applicable: load(), save() or saveAs().These methods return true for a successful action and false otherwise.The user must be able to supply a file name for the save() method, as the list may not have been read from a file previously. If the phone list has been modified but not saved, the user should be prompted to save the current phone list before opening another file or terminating the program. solutions 398 ■ CHAPTER 18 FUNDAMENTALS OF FILE INPUT AND OUTPUT ■ SOLUTIONS Exercise 1 // // fcopy.cpp // Copy files // Call: fcopy [ source [ destination ] ] // #include <iostream> #include <fstream> using namespace std; char usage[] = "Call: fcopy [source [destination]}"; inline void openerror( const char *file) { cerr << "Error opening the file " << file << endl; exit(1); } bool copy( istream& is, ostream& os), // Prototype, ok = true; // ok flag. int main(int argc, char *argv[]) { char source[256] = "", dest[256] = ""; switch( argc ) { case 1: // No file declared // ==> input file name. cout << "Copying source file to " "destination file!\n" "Source file: "; cin.getline( source, 256); if( strlen(source) == 0) { cerr << "No source file declared!" << endl; return 1; } cin.sync(); // No previous input cout << "Destination file: "; cin.getline( dest, 256); break; case 2: // One file is declared. strcpy( source, argv[1]); break; case 3: // Source and destination files are declared. strcpy( source, argv[1]); strcpy( dest, argv[2]); break; . you are already familiar. File input and output methods have been added to the class. A file stream that references a file opened in binary mode is passed as an argument to the methods read() and write() storage itself, allow- ing it to write internal status data while simultaneously preventing external access to that data. ᮀ Storing Account Class Objects The opposite page shows the Account class,. member object name is saved as a C string, that is, as a string terminated by the null character, ''. The << operator and the function getline() are available for this task. exercises 394 ■ CHAPTER

Ngày đăng: 06/07/2014, 17:21

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan