360 likes | 474 Views
Chapter 12: File Operations What is a File?. A file is a collection on information, usually stored on some electronic medium. Information can be saved to files and then later reused. File Names.
E N D
Chapter 12: File Operations What is a File? • A file is a collection on information, usually stored on some electronic medium. • Information can be saved to files and then later reused.
File Names • All files are assigned a name that is used for identification purposes by the operating system and the user. • Extensions .bat Dos batch file .doc Word file .cpp C++ source file .h C++ header file .obj Object file .exe Executable file .html (.htm) Hypertext Markup Language file .java Java source file .txt Text file
The Process of Using a File • Using a file in a program is a simple four-step process: • Declare the file. • Open the file. • If the file does not yet exist and it is opened for reading, this is an error. • If the file does not yet exist and it is opened for writing, the file is created. • If the file does exists and it is opened for writing, the existing file is deleted (and will be written over). • Read/write to/from the file. • Close the file.
Opening a File • You can declare a file in a separate statement and then open it. • For example: ifstream in; ofstream out; fstream inout; in.open("customer.in"); out.open("customer.out"); inout.open("customer.inout");
Opening a File at Declaration • A file may be opened at the same time it is declared. • For example: • ifstream in ("names.in"); • ofstream out ("names.out"); • fstream inout ("names.inout", ios::in | ios::out);
What are ios:in and ios::out? • They are actually constants that are thought of in binary. • If you want to see what values they have, you can just print them. They are integers.
They are each powers of two, so in binary there is just one bit that is a one. • The | is a binary “or”. Which means, the result is set if one or the other of the inputs is set. • For example: 0101 OR 0011 = 0111 • Thus, when we “or” the flags together, we produce a single binary number to pass as a parameter to the open method. Each bit that is set gives the method additional information (I want it opened as output and as input).
Testing for Open Errors • To see if the file is opened correctly • in.open("cust.dat"); if ( in==NULL ) { cout << "Error opening file named in.\n"; exit(1); } // if • Or as if ( in.fail() ) • or assert(in!=NULL) // remember #include <cassert>
Closing a File • System closes all files when a program finishes execution. • Note: Despite the above statement, a file should be closed when a program is finished using it. Space is released at that time. • Examples: • in.close(); • out.close();
Appending to a File – Program void main(void) { fstream dataFile; dataFile.open("demofile.txt", ios::out); dataFile << "Jones\n"; dataFile << "Smith\n"; dataFile.close(); dataFile.open("demofile.txt", ios::app); dataFile << "Willis\n"; dataFile << "Davis\n"; dataFile.close(); } // main
Detecting the End of a File • The eof() member function reports when the end of a file has been encountered. • In C++, “end of file” doesn’t mean the program is at the last piece of information in the file, but beyond it. • The eof() function returns true when there is no more information to be read
End-of-File – Program void main(void) { fstream dataFile; char name[81]; dataFile.open("demofile.txt", ios::in); assert (dataFile); dataFile >> name; while (!dataFile.eof()) {cout << name << endl; dataFile >> name; } // while dataFile.close(); cout << "\nDone.\n"; } // main
Passing File Stream Objects to Functions • File stream objects may be passed by reference to functions – the file might not change, but the pointer to the next location in it does. bool openFileIn ( fstream &file, char name[] ) { bool status; file.open( name, ios::in ); return( !file.fail() ); } // openFileIn
Error Testing – Program void showState(fstream &file) { cout << "File Status:\n"; cout << " eof bit: " << file.eof() << endl; cout << " fail bit: " << file.fail() << endl; cout << " bad bit: " << file.bad() << endl; cout << " good bit: " << file.good() << endl; file.clear(); } // showState
ostream reference – cout or fout The advantage of ostream is that you can easily change from printing to the console to printing to a file. For example, void output(ostream & out){ out << "Animal " << getName() << " moves by " << getMove() << getBlood(); out << endl; } Now if I call output(cout), it prints to the screen, but if I call output(myFile), it prints to myFile. It is very convenient for debugging as you can see the file on the screen, but then easily switch to a regular file at a later time.
Member Functions for Reading and Writing Files • File stream objects have member functions for more specialized file reading and writing. get – get a character from the input file. put – write a character to the output file.
Binary Files • Binary files contain data that is unformatted for printing (stored in internal form), and not necessarily stored as ASCII text. • A binary file is opened as file.open( "stuff.dat", ios::out | ios::binary );
Using a Binary File – Program void main(void) { ofstream file(“nums.dat", ios::binary); int buffer[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; cout << "Now writing the data to the file.\n"; file.write( reinterpret_cast<char*>buffer, sizeof(buffer)); file.close(); file.open("nums.dat", ios::in); cout << "Now reading the data back into memory.\n"; file.read( reinterpret_cast<char*>buffer, sizeof(buffer)); for (int count = 0; count < 10; count++) cout << buffer[count] << " "; file.close(); } // main
Warning • Don’t try to look at a binary file. • It will look like garbage, as data is stored in internal form rather than as printable characters.
Creating Records with Structures • Structures may be used to store fixed-length records to a file. struct Info { char name [LEN]; int age; char address1 [LEN]; char address2 [LEN]; char phone [LEN]; }; • Since structures can contain a mixture of data types, you should always use the ios::binary mode when opening a file to store them.
Files and Structures – Program do{ // get info cin.getline(person.phone, 14); … people.write( reinterpret_cast<char *>&person, sizeof(person)); } while (toupper(again) == 'Y'); people.close(); } // main reinterpret_cast<type> just changes the following variable to an entry of type “type”. Other kinds of casts may also work. void main(void) { ofstream people("people.dat", ios::binary);
Writing more than one file at a time • If you declare an array of structs, you can write them all in one statement • Example: • Person people[5];… people.write( reinterpret_cast<char *>people, sizeof(people)); • since people is already a pointer, you don’t need to take an address • Since sizeof(people) returns the size of the whole array, the whole array will be written.
Random Access Files • Random Access means non-sequentially accessing information in a file. – Accessing by location, rather than linearly. Example, how you sort mail into bins.
Random Access Member Functions • seekg – used with files opened for input (the g stands for get). • seekp – used with files opened for output (the p stands for put).
Using seekg – Program void main(void) { fstream file("letters.txt", ios::in); char ch; file.seekg(5L, ios::beg); file.get(ch); cout << "Byte 5 from beginning: " << ch << endl; file.seekg(-10L, ios::end); file.get(ch); cout << "Byte 10 from end: " << ch << endl; file.seekg(3L, ios::cur); file.get(ch); cout << "Byte 3 from current: " << ch << endl; file.close(); }// main
Other Member Functions • tellp returns a long integer that is the current byte number of the file’s write position. • tellg returns a long integer that is the current byte number of the file’s read position.
Opening a File for Both Input and Output • You may perform input and output on an fstream file without closing it and reopening it.
Creating a Inventory File – Program struct Invtry { char desc[LEN]; int qty; float price; }; void main(void) { fstream inventory("invtry.dat", ios::out | ios::binary); Invtry record = { "", 0, 0.0 }; // Okay for char arrays, not for strings for (int count = 0; count < 5; count++) { cout << "Now writing record " << count << endl; inventory.write( reinterpret_cast<char*>)&record, sizeof(record)); } // for inventory.close(); } // main
Display Inventory File – Program (cont) inventory.read( reinterpret_cast<char *>&record, sizeof(record)); while (!inventory.eof()) { cout << "Description: "; cout << record.desc << endl; cout << "Quantity: "; cout << record.qty << endl; cout << "Price: "; cout << record.price << endl << endl; inventory.read( reinterpret_cast<char *>&record, sizeof(record)); } // while inventory.close(); } // main
Edit Inventory – Program void main(void) {fstream inventory("invtry.dat", ios::in | ios::out | ios::binary); f.seekg(0L,ios::end); // set position to end int numBytes = f.tellg(); // get the number of bytes int numRecord = numBytes/sizeof(CensusStat); cout << "My Records size is " <<numRecord<< endl; Invtry record; long recNum; cout << "Which record do you want to edit?"; cin >> recNum; inventory.seekg(recNum * sizeof(record), ios::beg); inventory.read( reinterpret_cast<char *>&record, sizeof(record)); // update information inventory.seekp(recNum * sizeof(record), ios::beg); inventory.write( reinterpret_cast<char *>&record, sizeof(record)); inventory.close(); } // main