290 likes | 462 Views
Andreas Savva. Programming Principles II. Lecture Notes 7 Files. Letter.txt. Dear Ann I am now living in Cyprus where I got married and bought a house. This is a great place to be. The weather is perfect and life is. Files.
E N D
Andreas Savva Programming Principles II Lecture Notes 7 Files
Letter.txt Dear Ann I am now living in Cyprus where I got married and bought a house. This is a great place to be. The weather is perfect and life is . . . Files • A file is a group of organized data stored in secondary storage. • Every file has a filename – the name by which the operating system refers to the contents of the file.
Type of Files • The operating system usually distinguishes files in different categories: • Text file (contains ASCII characters) • Executable (Contains code of a program) • Binary file (contains arbitrary data) • Application programs usually store data in binary files in a format understood only by the specific application program e.g. • MS Word documents (.doc) • MS Excel files (.xls) • GIF image files (.gif)
File Handle in C++ • In order to be able to handle a file we need to: • include the library fstream. • declare an object to represent a file which will permit reading, writing, etc. • C++ provides the following classes to perform input and output from/to files: • ofstream: stream class to write in files • ifstream: Stream class to read from files • fstream: Stream class to read and write from/to files #include <iostream> #include <fstream> using namespace std; int main() { fstream myFile; . . . return 0; }
Opening a File • To open a file we must: • determine the file name (e.g. data.txt) • create a new file handle (e.g. myFile) • use the handle to open the file myFile.open(filename, mode) • To open an existing file to read from, the mode must be ios::in. #include <iostream> #include <fstream> using namespace std; int main() { fstream myFile; myFile.open(”data.txt”,ios::in); . . . return 0; }
Using fstream Objects • In using both ifstream and ofstream objects the mode, input or output, is implied by the object. Thus, • ifstream objects can only be used for input • ofstream objects can only be used for output • fstream objects can be used for input or output but require an explicit mode designation. #include <iostream> #include <fstream> using namespace std; int main() { ifstream inFile; ofstream outFile; fstream addFile; inFile.open(”in.txt”,ios::in); outFile.open(”out.txt”,ios::out); addFile.open(”new.txt”,ios::app); . . . return 0; }
Opening a File Mode • Mode is an optional parameter with a combination of the following flags: • All these flags can be combined using the bitwise operator OR (|). For example, the following will open a the file example.bin in binary mode to add data: fstreammyFile; myFile.open(”example.bin”, ios::out | ios::app | ios::bin);
Default Modes • Each one of the open() member functions of the classes ofstream, ifstream and fstream has a default mode that is used if the file is opened without a second argument, i.e. ofstreammyFile; myFile.open(”data.txt”); • The three classes have a constructor that takes the same parameters as open() and automatically calls it. ofstreammyFile(”data.txt”, ios::out);
Opening a File • File streams opened in binary mode perform input and output operations independently of any format considerations. • Non-binary files are known as text files, and some translations may occur due to formatting of some special characters (like newline and carriage return characters). • The method is_open() with no arguments (returns a bool value) can be called to check whether or not a file stream has successfully opened a file. ofstream myFile(”data.txt”); if (myFile.is_open()) { // ok, proceed with output } else cout << ”Unable to open file”;
data.txt data.txt 3458 Jurassic Park 34A58B Jurassic Park 458Jurassic3 4A58B3 Reading from a Text-File • Data output and input operations on text-files are performed in the same way as with cout and cin. #include <iostream> #include <fstream> using namespace std; int main() { ifstream inFile(”data.txt”); if (inFile.is_open()) { char ch; int k; char s[50]; inFile >> ch; inFile >> k >> s; cout << k << s << ch; } return 0; } Ignores spaces and control characters
Reading Methods • There exist a variety of methods for reading streams (files). • Read a single character, including spaces and control characters: ch = myFile.get(); • Read a line of text or up to 20 characters into array s[] : myFile.getline(s,20); • Read a line of text or up to 20 characters or until character ’A’ occurred into array s[] : myFile.getline(s,20,’A’); • cin is also a stream object; we can use the same operations: ch = cin.get(); cin.getline(s,20); cin.getline(s,20,’A’);
Exceptions and Errors • With file operations there may be a variety of problems, i.e. • File not found during opening. • File cannot be opened (already opened exclusively by other program). • End of file reached. • Disk full during writing. • Detecting when a problem occurred: !myFile myFile.fail() myFile.open("data.txt",ios::in); if (!myFile) // an error has occurred cout << ”Could not open file”; . . .
Checking State Flags • A number of bool member functions exist to check for specific states of a stream:
Closing a File • After completing the use of the file, it should be closed so that it resources become available again. • Closing a file: myFile.close(); • Once closing the file, the file becomes available to be opened by other processes and the stream object can be used to open another file. • In case that an object is destructed before is closed the destructor calls the member function close().
Reaching the End of File // the following program reads lines and displays // them on the screen until the end of the file. #include <iostream> #include <fstream> using namespace std; int main() { fstream myFile; char str[256]; myFile.open("data.txt", ios::in); if (myFile.is_open()) { while(!myFile.eof()) { myFile.getline(str,256); // get a line cout << str << endl; // display line } myFile.close(); } else cout << ”Unable to open file”; return 0; } • The method eof() determines if the end of the file is reached.
Using method good() // the following program reads lines and displays // them on the screen until the end of the file. #include <iostream> #include <fstream> using namespace std; int main() { fstream myFile; char str[256]; myFile.open("data.txt", ios::in); if (myFile.is_open()) { while(myFile.good()) { myFile.getline(str,256); // get a line cout << str << endl; // display line } myFile.close(); } else cout << ”Unable to open file”; return 0; } • The method good() can be used instead of the method eof() .
Writing to a File • Similar to opening for reading, but use ios::out when opening: myFile.open("data.txt", ios::out); • Consequences to file: • If the file does not exist, it is created. • If it exists its data is overwritten. • Writing to a file: myFile << ”Hello” << 12 << ’C’ << endl;
Copying a File to Another File #include <iostream> #include <fstream> using namespace std; int main() { fstream fin, fout; char str[256]; fin.open("data.txt", ios::in); if (fin.is_open()){ fout.open("newdata.txt", ios::out); while(!fin.eof()) { fin.getline(str, 256); // get a line fout << str << endl; // put a line } } fin.close(); fout.close(); return 0; }
Appending to a File • Data can be appended at the end of the file by using ios::app when opening. • Existing data will not be overwritten. myFile.open("data.txt", ios::app);
newdata.txt data.txt My name is George and I live in London. ?y name is ?eorge and ? live in ?ondon. Constant EOF #include <iostream> #include <fstream> using namespace std; int main() { fstream fin, fout; char ch; fin.open("data.txt", ios::in); if (!fin) cout << "File not found"; else { fout.open("newdata.txt", ios::out); ch = fin.get(); while(ch != EOF) { if (ch >= ’A’ && ch <= ’Z’) fout << ’?’; else fout << ch; ch = fin.get(); } fin.close(); fout.close(); } return 0; } Character denoting the end of file
Stream Pointers: get and put • All i/o stream objects have, at least, one internal stream pointer: • ifstreams like istream, has a pointer known as get pointer that points to the element to be read in the next input operation. • ofstreams like ostream, has a pointer known as put pointer that points to the location where the next element will be written. • These internal stream pointers that point to the reading or writing locations within a stream can be manipulated using the following member functions: • tellg() and tellp() – These two functions return a value of the member type pos_type, which is an integer data type, representing the current position of the respective pointer. • seekg(position) and seekp(position) – These functions change the position of the respective pointers. The pointer is changed to the absolute position (counting from the beginning of the file). Parameter position is of member type pos_type (integer).
data.txt My name is George and I live in London. My nameand I live in London Stream Pointers #include <iostream> #include <fstream> using namespace std; int main() { ifstream fin(”data.txt”); if (fin.fail()) cout << "File not found"; else { char ch; while(ch = fin.get(), ch != EOF) { cout << ch; if (fin.tellg()==fstream::pos_type(7)) fin.seekg(18); } fin.close(); } return 0; }
Overloaded Methods forchanging the Stream Pointers • There is an overloaded function for both member functions seekgand seekp: seekg( offset, direction ) seekp( offset, direction ) • The position of the get or put pointer is set to an offset value relative to some specific point determined by the parameter direction. Parameter offset is of the member type off_type, which is an integer type and direction is of type seekdir which is an enumerated type that determines the point from where offset is counted from, and that can take any of the following values:
Changing the Stream PointersExamples Display the size of the file: myFile.seekg(0, ios::end); long size = myFile.tellg(); cout << ”Size is ” << size << ” bytes”;
abroad amsterdam and around and amazing Unget Character Display the words starting with ‘a’: data.txt int main() { ifstream fin("data.txt"); if (fin.fail()) cout << "File not found"; else { char ch, s[100]; ch=fin.get(); fin.unget(); if (ch == 'a') { fin >> s; cout <<s<<endl; } while (ch=fin.get(), ch!=EOF) { if (ch == ' ') { ch = fin.get(); if (ch == 'a') { fin.seekg(-1,ios::cur); fin >> s; cout << s << endl; } } } fin.close(); } return 0; } i traveled abroad to amsterdam and i was very happy to go around and see this amazing city fin.unget();
Binary Files • In binary files, to input and output data with the extraction and insertion operators (<< and >>) and functions like getline is not efficient, since there is no need to format data, and data my not use the separation codes used by text-files to separate elements (like spaces, newlines, etc.) • For binary files, file streams include two member functions for input and output. read( char*memory_block, int size ) – ifstream, fstream write( char*memory_block, int size )– ofstream, fstream • where memory_block is the address of an array of bytes and size is an integer.
Writing Structures to Binary Files class human { public: human(){} human(char s[], int x) { strcpy(name,s); age = x; } private: char name[50]; int age; }; void write_to_file() { char name[50]; int age; cout << "Enter name and age: "; cin >> name >> age; human person(name,age); ofstream myFile("data.bin", ios::app | ios::binary); myFile.write((char*)&person, sizeof(human)); myFile.close(); }
Reading Structures from Binary Files void read_from_file(human people[], unsigned long &n) { ifstream myFile("data.bin", ios::binary); if (myFile.fail()) cout << "File not found"; else { myFile.seekg(0,ios::end); n = myFile.tellg()/sizeof(human); myFile.seekg(0); for (unsigned long i=0; i<n; i++) myFile.read((char*)&people[i], sizeof(human)); myFile.close(); } } Reading records one-by-one void read_from_file(human people[], unsigned long &n) { ifstream myFile("data.bin", ios::binary); if (myFile.fail()) cout << "File not found"; else { myFile.seekg(0,ios::end); n = myFile.tellg()/sizeof(human); myFile.seekg(0); myFile.read((char*)people, sizeof(human)*n); myFile.close(); } } Reading records all at once
Buffers and Synchronization • File streams are associated to an internal buffer of type streambuf. This buffer is a memory block that acts as an intermediary between the stream and the physical file. For example, with an ofstream, each time the member function put (which writes a single character) is called, the character is not written directly to the physical file with which the stream is associated. Instead, the character is inserted in the stream’s intermediate buffer. • When the buffer is flushed, all the data contained in it is written to the physical medium (if it is an output stream) or freed (if it is an input stream). This process is called synchronization and takes place under the following circumstances: • When the file is closed: before closing a file all buffers that have not yet been flushed are synchronized and all pending data is written or read to the physical medium. • When the buffer is full: Buffers have a certain size. When the buffer is full it automatically synchronized. • Explicitly, with manipulators: When certain manipulators are used on streams, an explicit synchronization takes place. These manipulators are: flush and endl. • Explicitly, with member function sync(): calling stream’s member function sync(), which takes no parameters, causes an immediate synchronization. This function returns an int value equal to -1 if the stream has no associated buffer or in the case failure. Otherwise (if successful) it returns 0.