C++ Basics Tutorial - Lesson 11
Related Blog Items
- C++ Basics - Tutorial
- C++ Tutorial Part 2 - Advanced
- C++ Advanced Tutorial - Lesson 11
- C++ Advanced Tutorial - Lesson 8
- C++ Advanced Tutorial - Lesson 3
Please refer lesson 10..
11. File Processing
11.1 Data Hierarchy
11.2 Primary Key
11.3 Files and Streams
11.4 File Open Modes
11.5 Checking open and input success
11.6 Method exit
11.7 File Position Pointer
11.8 Sequential Access File
11.9 Random Access File and Object Serialization
11.10 File and Directory Manipulation
11. File Processing
11.1 Data Hierarchy
Field a group of characters conveying meaning
Record composed of several fields (in C++ called members), such as structure or class
File a group of related records
Database a group of related files
A collection of programs designed to manage database is called a Database Management System (DBMS).
11.2 Primary Key
To facilitate the retrieval of specific records from a file, at least one field in each record should be chosen as a primary key. A primary key represents something unique of each entry, such as account number of bank customers, so that all entries can be uniquely identified by their record keys.
11.3 Files and Streams
The source of input may be keyboard, files on hard disk or other devices. The output destination may be screen, files on hard disk or other devices.
For standard IO devices keyboard and screen, C++ provides iostream objects cin, cout, cerr, clog. For other devices, you have to create objects yourself.
An ifstream object can be used to input from a file on disk, an ofstream object can be used to output to a file on disk. A fstream object can be used both to input from and output to a file. You can use their methods open and close to open and close a certain file. For example, you can use
ofstream file1("Frank.txt", ios::out);
or you can use
ofstream file1; file1.open("Frank.txt", ios::out);
You can also create a fstream object, which can be used for both input and output:
fstream file("Frank.txt", iso::out | ios::in);
The file connected to an object of ifstream, ofstream or fstream class will be automatically closed when the object leave scope and is destroyed. However, it is a good practice to explicitly close the file as soon as you do not use it any longer. Reasons are:
Reduce resource usage;
Improve the program’s clarity;
Prevent future misuse.
11.4 File Open Modes
When opening a file, you can pass together with file name the following open modes:
ios::app //Append output to the end of the file ios::ate //Open a file and move the file position pointer to the end of the file. //Normally used for starting at appending data, but by moving the file //position pointer, data can be written anywhere in the file ios::in //Open a file for input ios::out //Open a file for output -- existing data in the file will be lost. //If no such file, will create one ios::trunc //Discard the file's existing contents (same as ios::out) ios::nocreate //Do not create new files -- if no such file then open operation fails ios::noreplace //Do not replace -- if file exists then open operation fails
By default, ofstream files are opened for output (ios::out), and ifstream files are opened for input (ios::in).
11.5 Checking open and input success
Overloaded ios operator method “operator!” is used to check the success of file opening. It returns nonzero (true) when either failbit or badbit is set for the stream on open operation, either for input or output. Some possible errors are attempting to open a nonexistent file for reading, to open a file for reading without permission, to open a file for writing when no disk space is available. Example:
ostream file1( Test.txt ); if(!file1) { cerr << "Can't open file! \n"; exit(1); }
Another overloaded ios operator method operator void* is used to check the success of stream input. It converts the IO stream into a pointer so it can be tested as 0 or nonzero. If failbit or badbit is set for the stream, 0 is returned. When EOF is encountered during input, failbit is set for cin. Example:
while(cin>>a) while(file>>a)
the condition in the while header automatically invokes the operator void* method. When EOF is inputted from keyboard or encountered in file1, 0 is returned and the while loop will stop.
11.6 Method exit
Method exit is called to end the program. Its argument is returned to the OS so that it can respond appropriately to the error. Argument 0 indicates that program terminates normally, other nonezero values indicate that program terminates due to error.
11.7 File Position Pointer
The value of the file position pointer is the number of the byte which is to be inputted or outputted. It can also be called “offset”. To set this pointer for ifstream object, use method “seekg”. For ofstream objects, use “seekp”. The arguments of these two methods is normally a long integer.
A second argument can also be passed to the methods as origin of the offset:
15f988c6ab573fea7258c4f4e6a5222f006
Example:
file1.seekg(0); // beginning of the file
file1.seekp(n, ios::cur) // nth byte from current position
file1.seekg(n, ios::end) // nth byte from the end of file
file1.seekp(0, ios::end) // last byte in the file
To get the current position of the file position pointer, use method “tellg” for ifstream objects and “tellp” for ofstream:
long location = file1.tellp();
If you open a file for both input and output:
fstream file( Frank.txt , ios::in | ios::out);
you can write into it, relocate the file position pointer, then read from it, vice versa.
11.8 Sequential Access File
In computer’s internal memory, different integers such as 7 or 7777 are stored with the same number of bytes. But in a file they are stored in different sizes. Therefore, when you overwrite an original number with a longer one in a file, it will overwrite the following field.
For this reason, this kind of files which store data in varied length are called “sequential access files”. You have no idea on exactly how long each record occupies. Therefore, to find a particular record in the file, you have to read from the first one sequentially until you reach the one you want. You can not jump to a certain record directly. If you want to modify a record in the middle of the file, unless the length of the record is not changed, you have to first copy the records before the one to be updated into a file, then append the updated record to that file, then append the records following the updated one to the file.
11.9 Random Access File and Object Serialization
Random access file is opened in the same way as normal files, but the way to write data in it is different. Complete objects instead of primitives are read or written with class iostream s method read and write. The object to be read and written can contain member objects, pointers and references to other objects, and other objects can again contain member objects, pointers and references. Method write will write everything necessary into the file, including the type information and the whole network of objects, so that later method read can recover it. The process of breaking an object into data stream is called object serialization .
There is one restraint: the object to be serialized and all its network objects should all have fixed size. If the class contains a char * data member, because the length of the string is variable, method write can not properly allocate space for each record, and run-time error may happen. In such a case, use char [ ] instead of char *.
Method read and write have the same functionality as Java s readObject and writeObject method of class ObjectInputStream and ObjectOutputStream.
Because you can not decide the format or sequence of each field, this way of IO is also called unformatted IO, whereas conventional way of IO is called formatted IO.
Method write takes two arguments. First argument is the address of the object to be serialized, and it should be casted to the type of “const char *” type. The second argument is an integer of size_t specifying the number of bytes of the record. Keyword sizeof can be used to get this size.
Method read has similar arguments as write, except that the pointer type is char * .
file.write(reinterpret_cast<const>(&recordName), sizeof(recordName)); file.read(reinterpret_cast<char>(&recordName), sizeof(recordName));
The position to start reading or writing is decided by file position pointer, which is set by seekg for inputting files and seekp for outputting files.
#include "iostream.h" //class Base class Base { public: Base(const int = 0); Base(const Base &); const int get() const; protected: const Base & operator=(const Base &); private: int member; }; Base::Base(const int i): member(i) {} Base::Base(const Base & b): member(b.member) {} const Base & Base::operator=(const Base & rv) { member = rv.member; return *this; } const int Base::get() const { return member; }
//class Derived class Derived : public Base { public: Derived(const int = 0, const int = 0); Derived(const Derived &); const Derived & operator=(const Derived &); void print() const; private: int member; }; Derived::Derived(const int i1, const int i2) : Base(i1), member(i2) {} Derived::Derived(const Derived & d) : Base(d), member(d.member) {} const Derived & Derived::operator=(const Derived & rv) { member = rv.member; Base::operator=(rv); return *this; } void Derived::print() const { cout << "Base member is " << Base::get() << endl; cout << "Derived member is " << member << endl; }
//class ClientData class ClientData { public: ClientData(int = 0, Derived * = 0); int getId() const; void print() const; private: int id; Derived * derived; }; ClientData::ClientData(int i, Derived * d): id(i), derived(d) {} int ClientData::getId() const { return id; } void ClientData::print() const { cout << id << ": "; derived->print(); }
//main int main(int argc, char* argv[]) { Derived d1(111, 222); ClientData c1(37, &d1); cout << "Client c1 = \n"; c1.print(); cout << "\n"; fstream file("customerfile.txt", ios::out | ios::in); int size = sizeof(ClientData); file.seekp(c1.getId() * size); file.write(reinterpret_cast<const>(&c1), size); file.close(); file.open("customerfile.txt", ios::out | ios::in); ClientData empty; // create an empty object file.seekg(37 * size); file.read(reinterpret_cast<char>(∅), size); cout << "Empth is now:\n"; empty.print(); file.close(); return 0; }
Output will be:
Client c1 =
37: Base member is 111
Derived member is 222
Empth is now:
37: Base member is 111
Derived member is 222
In this example, data member “id” of class ClientData acts as the primary key.
11.10 File and Directory Manipulation
Win32 API provides a set of functions to manipulate files and directories. They are listed in MSDN under title “About File I/O”. Following is a very useful piece of code which go through all sub-directories of the current directory, and change replace a certain string with another in all files that conform to a certain file name filter:
#define SUBSTR1 "ulStatus = RET_EXCEPTION" // length = 24, not counting NULL #define SUBSTR2 "ulStatus = RET_EXCEPTION" // length = 25, not counting NULL #define SUBSTR3 "ulStatus = RET_EXCEPTION" // length = 25, not counting NULL ULONG g_ulId = 0x0001; void CSearchFilesDlg::ProcessFindData(WIN32_FIND_DATA *pFindData) { if(pFindData->dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY) { // Check whether the sub-directory is "." or "..". If yes do nothing if(strcmp(pFindData->cFileName, ".") != 0 && strcmp(pFindData->cFileName, "..") != 0) SearchDir(pFindData->cFileName); // Call recursively } else { // Acquire extension name e.g. ".cpp" char * strExtName = strchr(pFindData->cFileName, '.'); if(strExtName) { if(strcmp(strlwr(strExtName), ".cpp") == 0) ProcessFile(pFindData->cFileName); // Just we want. Process it. } } } void CSearchFilesDlg::SearchDir(LPCTSTR subDirName) { if(subDirName != NULL) { SetCurrentDirectory(subDirName); GetCurrentDirectory(PATH_STR_LENGTH, m_strPath); // Indicate whether a sub-directory has been entered. If yes, after // finishing searching we should exit it. m_fSubDirEntered = TRUE; } WIN32_FIND_DATA findData; // structure to hold all attributes about the file HANDLE h = FindFirstFile("*.*", &findData); // Handle h is used to close file ProcessFindData(&findData); while(FindNextFile(h, &findData)) ProcessFindData(&findData); FindClose(h); if(m_fSubDirEntered) { SetCurrentDirectory(".."); // Exitting sub-directory // Definition in header file: char m_strPath[PATH_STR_LENGTH]; GetCurrentDirectory(PATH_STR_LENGTH, m_strPath); } }
void CSearchFilesDlg::ProcessFile(LPCTSTR fileName) { CFile fileOrigin(fileName, CFile::modeRead | CFile::shareExclusive); CArchive arOrigin(&fileOrigin, CArchive::load); CFile fileTemp("TempStore.cpp", CFile::modeWrite | CFile::modeCreate | CFile::shareExclusive); CArchive arTemp(&fileTemp, CArchive::store); char strLine[1000]; char * strSub = NULL; char strReplace[80]; while(arOrigin.ReadString(strLine, 999)) { // Acquire a char * starting from substring "ulStatus = RET_EXCEPTION" strSub = strstr(strLine, SUBSTR1); if(strSub) { // If g_ulId is 0x7a, strReplace will be "007a007a" sprintf(strReplace, "ulStatus = 0x%.4x%.4x ", g_ulId, g_ulId); g_ulId++; // the sub-string will become "ulStatus = 0x007a007a " memcpy(strSub, strReplace, 24); } else { strSub = strstr(strLine, SUBSTR2); if(strSub) { sprintf(strReplace, "ulStatus = 0x%.4x%.4x ", g_ulId, g_ulId); g_ulId++; memcpy(strSub, strReplace, 25); } else { strSub = strstr(strLine, SUBSTR3); if(strSub) { sprintf(strReplace, "ulStatus = 0x%.4x%.4x ", g_ulId, g_ulId); g_ulId++; memcpy(strSub, strReplace, 25); } } } arTemp.WriteString(strLine); arTemp.WriteString("\n"); } arOrigin.Close(); fileOrigin.Close(); arTemp.Close(); fileTemp.Close(); // Delete the original file and rename the temp file to it DeleteFile(fileName); MoveFile("TempStore.cpp", fileName); } void CSearchFilesDlg::OnStartSearch() { SearchDir(); msg("Searching completed!"); }
Popularity: 23%
You need to log on to convert this article into PDF
Related Blog Items - C++ Basics - Tutorial
- C++ Tutorial Part 2 - Advanced
- C++ Advanced Tutorial - Lesson 11
- C++ Advanced Tutorial - Lesson 8
- C++ Advanced Tutorial - Lesson 3
Related Blog Items
- C++ Basics - Tutorial
- C++ Tutorial Part 2 - Advanced
- C++ Advanced Tutorial - Lesson 11
- C++ Advanced Tutorial - Lesson 8
- C++ Advanced Tutorial - Lesson 3
thanks for your tutorial, i have a question here, how to open a excel file of my disk and print it on the screen? any information or source code? i read the c++ book, but can’t complete this it. thanks a lot
January 11th, 2008 at 8:52 am
opening excel file no different than opening any other file, so for printing it you should know the format of the excel (file format), otherwise you may search for any API from the microsoft on excel
January 11th, 2008 at 6:20 pm
I want to get interview questionn related to IT , C/C++, Database, ASP.net, C#, SQL Server
June 12th, 2008 at 12:00 pm