CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 3 of 3
  1. #1
    Join Date
    Feb 2006
    Posts
    2

    Changing a record in a text file.

    I'm new here. I've been working on an assignment that performs a number of operations on a text file via fstream. In one option, the program retrives a single record out of a text file (using seekg()) and re-writes another record over it. My problem is, I can read the specified record from the stream, but the new record is still appended to the end of the file rather than overwriting the one chosen.

    Here is the code. Note that I have removed much of it (read: the working parts) for simplicity.

    Code:
    class Person{
    protected:
        char fName[20];
        char lName[30];
        long age;
        double wage;
        int deleted;
    
    public:
    	Person() {fName[0] = 'x'; lName[0] = 'x'; age = 1; wage = 1.0; deleted = 0;} // constructor
    
    	void getinfo(){		//- prompts for, gets input and sets deleted to 0.
    		
    		cout << "Enter First Name: "; cin >> fName;
    
    		cout << "Enter Last Name: "; cin >> lName;
    		
    		cout << "Enter Age: ";
    		while(1){
    			while(!getlong(age))
    				cout << "**** Invalid integer **** - re-enter: ";
    				
    			if(age > 0)
    				break;
    
    		    cout << "Age must be greater than 0 - please re-enter: ";
    		}
    
    		cout << "Enter Wage: ";
    		while(1){
    			while(!getdoub(wage))
    				cout << "**** Invalid integer **** - re-enter: ";
    				
    			if(wage > 0)
    				break;
    
    		    cout << "Wage must be greater than 0 - please re-enter: ";
    		}
    
    		deleted = 0;
    	}
    
    	void dispinfo(){	//- displays data contained in class data members except deleted
    		if(deleted == 0){
    			cout << "First Name: " << fName << ", "
    				 << "Last Name: " << lName << ", "
    				 << "Age: " << age << ", "
    				 << "Wage: " << wage << ", "
    				 << "Deleted: ";  
    			if (deleted == 1)
    				cout << "yes";
    			else
    				cout << "no";
    				 
    			cout << endl;
    		}
    	}
    
    	int dDeleted(){		//- simply returns the contents of the deleted data member
    		return deleted;
    	}
    
    	void deleteIt(){	//- simply sets the data member deleted to 0.
    		deleted = 0;
    	}
    
    	void unDeleteIt(){	//- simply sets the data member deleted to 1.
    		deleted = 1;
    	}
    };
    
    
    int main(){
    	Person pers;                   //create person variable
    	fstream f;  //create stream
                
    	int a, b, r;
    	int endPos, count, pos;
    	char ans;
    	
    	// FILE SETTINGS
    	cout << "Append to file, or recreate file?" << endl
    		 << "1. Append" << endl
    		 << "2. Recreate" << endl;
        while(1){
    		while(!getint(b))
           		cout << "**** Invalid integer **** - re-enter: ";		
    
    		if (b == 1 || b == 2)
    			break;
    		else
    			cout << "Pick a number 1-2: ";
    	} 
    	
    	if(b == 1)
    		f.open("person.txt", ios::in|ios::out|ios::binary|ios::app); 
    	else if(b == 2)
    		f.open("person.txt", ios::in|ios::out|ios::binary|ios::trunc); 
    	else{
    		cout << "Error: ending program";
    		return 0;
    	}
             // FILE SETTINGS
    
    
    	// MAIN PROGRAM LOOP
    	while(1){ 
    		
    		// MENU 
    		cout << "1. Read a record" << endl
    			 << "2. Change a record" << endl
    			 << "3. Delete a record" << endl
    			 << "4. Undelete a record" << endl
    			 << "5. Total record count on file" << endl
    			 << "6. Exit program" << endl << endl;
    
    		cout << "Enter Choice -> ";
    		// This part works. Removed for simplicity.
    
    
    		switch (a){ // MENU CHOICES
    			// Read a record
    			case 1:
    				//This part works. Removed.
    				break;
    			
                            /////////////////////////////////////////
                            ///////// START BAD CODE /////////
    			case 2: // Change a record	
    				f.clear();
    				f.seekg(0, ios::end);          // set to end.
    				endPos = f.tellg(); 
    				count = endPos / sizeof(Person); //cout << count;
                    //cout << "Record count: " << count << endl;
    
    				cout << "Change record number: "; 
    				while(1){
    					while(!getint(r))
           					cout << "**** Invalid integer **** - re-enter: ";
    					
    					if(r > 0 && r <= count)
    						break;
    
    					cout << "Pick a number 1-" << count << ": ";
    				}				
    				f.clear();                                   // clears the data stream
    				f.seekg(((r - 1) * sizeof(pers)), ios::beg);          // moves to 2nd record - 0=1, 1=2
    				//*** READING THE RECORD WORKS JUST FINE...
    				f.read((char*)&pers, sizeof(pers));				 //reads info at seeked position
    
    				cout << "\n\nHere is the info of record 2: \n";
     				pers.dispinfo();                           	// shows data in record
    				cout << "\nEnter Info to change below\n";
    				pers.getinfo();								//gets new data
      				f.clear();                                  // clears the data stream of errors
    				// *** I've tried both seekg() and seekp(), as shown below. Neither work here.
                                    f.seekg(((r - 1) * sizeof(pers)), ios::beg); f.tellg();         // repositions to 2nd record - 0=1, 1=2
    				f.seekp(((r - 1) * sizeof(pers)), ios::beg); f.tellp();        // repositions to 2nd record - 0=1, 1=2
                                    // *** This writes to the END of the file, not to the position I need.
    				f.write((char*)&pers, sizeof(pers));              // writes the record
    				cout << endl << "record has been re-written";
    								
                    break;
    
    			//cases 3 - 6 removed: 
    
    			
    		} // END MENU CHOICES
    	} // END MAIN PROGRAM LOOP
    	f.close();
    	getch();
    	return 0;
    }
    
    int getint(int & getnum)
    {
    	cin >> getnum;
        if( cin.good()){
       		cin.ignore(10, '\n');
    		return 1;
        }
        cin.clear();
        cin.ignore(10, '\n');
        return 0;
    }
    The sad part is, I copied the code right out of another, working cpp file provided to us by the instructor, only changing the variable and class function names to suit my needs. Here is the original:

    Code:
    //****  going to change the 2nd record
    	f.clear();                                   // clears the data stream
    	f.seekg((1 * sizeof(p)), ios::beg);          // moves to 2nd record - 0=1, 1=2
          //*** remember counting starts at 0 not 1!
        f.read((char*)&p, sizeof(p));				 //reads info at seeked position
    
        cout << "\n\nHere is the info of record 2: \n";
     	p.showdata();                           	// shows data in record
        cout << "\nEnter Info to change below\n";
        p.getdata();								//gets new data
      	f.clear();                                  // clears the data stream of errors
    	f.seekg((1 * sizeof(p)), ios::beg);         // repositions to 2nd record - 0=1, 1=2
    	f.write((char*)&p, sizeof(p));              // writes the record
    	cout << endl << "record has been re-written";
    This works perfectly. The only thing I'm really doing different is using append (opening my file for trunc kills the contents, making the code useless) and using it within a switch block.

    I've been going over this for days now, and I can't figure it out. This is pretty much a last resort. Can anyone give me a hint?

  2. #2
    Join Date
    Jan 2004
    Location
    Düsseldorf, Germany
    Posts
    2,401

    Re: Changing a record in a text file.

    Quote Originally Posted by LordBob
    This works perfectly.
    Surprisingly, as the code sets the wrong pointer (seekg instead of seekp).
    Quote Originally Posted by LordBob
    The only thing I'm really doing different is using append (opening my file for trunc kills the contents, making the code useless)...
    Well, that's your problem. The ios::app bit translates to "(append) Seek to the end of the stream before each output operation." So, there you have it. Don't pass the ios::trunk bit but don't pas the ios::app bit either.

  3. #3
    Join Date
    Feb 2006
    Posts
    2

    Re: Changing a record in a text file.

    Surprisingly, as the code sets the wrong pointer (seekg instead of seekp).
    Oh, I agree. I thought it was wrong myself, but it worked fine. It's just what the professor gave us.

    So, there you have it. Don't pass the ios::trunk bit but don't pas the ios::app bit either.
    Thanks a bunch. I'll try closing the file, then reopening without those bits.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured