CS 228 meeting -*- Outline -*- * file input/output (DD 14.3-11, HR A-93-95, A-101-111) needed to have data be persistent (last beyond execution of program): e.g., when the machine crashes ** overview summary: is read DD chapter 14! ------------------------------------------ FILE PROCESSING IN C++ (DD 14.3-11, HR A-93-95, A-101-111) Topics: Files and Streams Sequential Access files Random Access files Motivating problem: power failure at the hotel Essentials: #include #include ofstream outFile("output.txt"); ifstream inFile("input.txt"); int i; inFile >> i; outFile << i; outFile.write((char*)&i, sizeof(i)); inFile.read((char*)&i, sizeof(i)); ------------------------------------------ the first ones are for sequential access, the latter for random access. ** files and streams (DD 14.3) ------------------------------------------ FILE STREAMS def: a *stream* is a sequence of characters, indefinitely long Stream n bytes long: 0 1 2 3 4 5 6 7 n-1 [ | | | | | | | | ... | | | def: a *file* is a permenent collection of data. def: an *input file stream* is def: an *output file stream* is File states: nonexistent not in use | / ^ | open / | close v v | opened --> reading/writing ------------------------------------------ Q: How many characters are in cin? as many as someone is willing to type. similarly a program can output as many characters as it likes to the output ... a stream for which input is taken from a file (ifstream in C++) ... a stream to which output modifies a file (ofstream in C++) *** input from files (DD 14.5) ------------------------------------------ // countChars.C #include #include #include main() { ifstream inFile("test.txt"); if (!inFile) { cerr << "Cannot open " << "test.txt" << endl; return 1; } char ch; int count = 0; while (inFile >> ch) { count++; } cout << "There are " << count << " non-whitespace chars in " << "test.txt" << endl; return 0; } ------------------------------------------ Try this out on-line. ///// Fix it to give better error messages, by using operating system error number and messages The declaration of strerror is in , this is useful to print a good error message such as "No such file or directory". #include #include ... if (!inFile) { cerr << "Cannot open " << "test.txt" << ": " << strerror(errno) << endl; return 1; } ///// *** subtyping (DD p. 655) ------------------------------------------ SUBTYPING AMONG I/O TYPES ios istream ostream ifstream ofstream Example: extern istream& operator >>(istream& in, char & ch); ifstream inFile("my_data.txt"); inFile >> ch; def: type S is a *subtype* of T iff objects of type S can be used ------------------------------------------ ... whereever objects of type T can be. e.g., an ifstream can be used as an istream, so ifstream is a subtype of istream *** output to files (DD 14.4)) ------------------------------------------ PROBLEM Write a program that reads guest info from the terminal and stores it in a file guestDB.txt // Recovery.C #include #include #include #include #include "GuestInfo.h" #include "IODetails.h" main() { cout << "Guest Data recovery" << endl; const char dbname[] = "guestDB.txt"; return 0; } ------------------------------------------ ... ofstream outFile(dbname, ios::out | ios::noreplace); if (!outFile) { cerr << "Cannot open " << dbname << ": " << strerror(errno) << endl; return 1; } GuestInfo g; while (cin >> g) { outFile << g.name << endl; outFile << " "<< g.address << endl; outFile << " " << g.roomNumber << endl; outFile << " " << g.charges << endl; } work it out on-line, try it, show the effect of leaving in or out the ios:noreplace see DD p. 655 for list of these flags. The ios:: prefix names the class ios, and some name in it. How is closing the file handled? by the destructor, which calls close. You can also do it yourself: outFile.close(); good to do that when done. look at the IODetails files if time. ** sequential vs. random access files (DD 14.5-10) ------------------------------------------ SEQUENTIAL VS. RANDOM ACCESS FILES (DD 14.5-10) def: in *sequential access*, it takes linear time to access each record. def: in *random access* it takes constant time to access each record. ------------------------------------------ most files can be accessed randomly on Unix, exceptions are terminals. typically it's only practical to access a file randomly if all the data records have the same length (like an array) *draw picture* *** operations (DD p. 660) ------------------------------------------ RANDOM ACCESS PRIMITIVES (DD p. 660) File as a sequence of bytes: 0 1 2 3 4 5 6 7 n-1 [ | | | | | | | | ... | | | file position pointer: [ ] To start reading from beginning: To skip to byte n: To move forward n bytes: To get the curent position: ------------------------------------------ ... inFile.seekg(0); inFile.seekg(0, ios::beg); inFile.seekg(n, ios::beg); inFile.seekg(n, ios::cur); long location = inFile.tellg(); *** example of random access files (compare DD 14.8) key line: outFile.write((char*)&blankGuest, sizeof(GuestInfoFixed)); ------------------------------------------ FIXED SIZE RECORDS // GuestInfoFixed.h #ifndef _GuestInfoFixed_h #define _GuestInfoFixed_h 1 const int STRSIZE = 100; struct GuestInfoFixed { char name[STRSIZE+1]; char address[STRSIZE+1]; int roomNumber; float charges; }; #endif ------------------------------------------ ------------------------------------------ // GuestFileCreation.C #include #include #include #include #include "GuestInfoFixed.h" #include "IODetails.h" main() { cout << "Guest File Creation" << endl; const char dbname[] = "guestDB.txt"; ofstream outFile(dbname, ios::out | ios::noreplace); if (!outFile) { cerr << "Cannot open " << dbname << ": " << strerror(errno) << endl; return 1; } GuestInfoFixed blankGuest = {"", "", 0, 0.0}; const int MAX_ROOM_NUM = 99; int i; for (i = 0; i <= MAX_ROOM_NUM; i++) { outFile.write((char*)&blankGuest, sizeof(GuestInfoFixed)); } return 0; } ------------------------------------------ draw picture of this, run it, and look at size of file if time, talk about how to read, using inFile.read((char *)&g, sizeof(g)); See DD 14.11 for more details, or take Com S 361!