Thread: How to Reset a text file to bof??

  1. #1
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    Question How to Reset a text file to bof??

    Hi,

    I'm wondering how to reset a text file (ifstream infile("blah.txt")) to the beginning of the file using C++ (no C) after you've been working through it with some getline's.

    From what I've read, it seems to be a bit easier to work with files in C using the FILE type and all the functions that go w/it but I really want to know how to do it in C++ with no old headers.

    Thanks for your help.

    Swaine777
    Last edited by Swaine777; 05-03-2004 at 11:00 AM.

  2. #2
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    File streams, at least ifstreams, have a seekg method that is use to repoint the get pointer for that stream. I.e. to read through a file twice you would do something along the lines of:
    Code:
    #include <fstream>
    using namespace std;
    
    int main()
    {
        ifstream infile("Blah.Txt");
    
        // Loop through file once getting data, doing stuff, etc...
    
        infile.seekg(0,ios::beg);  // Seek to 0 bytes from the beginning of the file, i.e. the beginning
    
        // Loop through the file a second time doing more stuff...
    
        return 0;
    }
    Code not tested but I think that is the general idea.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  3. #3
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    thanks

    Thanks, I'll give it a shot.

  4. #4
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    Question

    Hi,

    I tried the infile.seekg(0, ios::beg); and it compiled fine but i'm not getting the result I was hoping for. Think you can take a look at my function and find the bug? I've got to figure out how to debug.

    So far the program does a good job of scanning through verses.txt and lists the references for the verses in this file but then I want the user to be able to choose one of the verses in the text file and have it display the chosen reference and verse contents on the screen.

    Here's a sample of the text file contents:

    Code:
    |Romans 3:23
    For all have sinned
    and fall short
    of the glory of 
    God
    
    |acts 1:8
    and you shall receive
    power when the Holy
    Spirit comes upon you
    and you shall be my witnesses
    
    |Romans 1:21
    For me to live is Christ
    and to die is gain

    and here is my function...


    Code:
    void SearchForVerse()
    {
        ifstream infile("verses.txt");
        string refs[30], dummy, chosenRef, aRef;
        int i = 0,      //counter
            pipePos,    //pipe position in string  
            verseChoice;  //which verse to display
        
        system("cls");
        cout << "Here are the references for the verses stored in verses.txt...\n\n";
        
        while(!infile.eof())
        {
            getline(infile, dummy, '\n');       //read in line up to new line char
            int dummySize = dummy.size();       //compute size of string
            pipePos = dummy.find('|', 0);       //find pipe starting at position 0
            if(pipePos == 0)                    //if the first char is a pipe...
            {
                refs[i] = dummy.substr(1, dummySize);   //take the rest of string as a ref
                i++;                                    //increment for ref array
            }
        }
        
        for(int p=0; p<i; p++)
            cout << p+1 << ". " << refs[p] << endl;
            
        //Works great up to this point!
        //The next chunk of code doesn't do anything...just a couple of pauses.
         
        cout << "\n\nChoose a verse to display: " << flush;
        cin >> verseChoice;                 //eventually will have error-checking here
        
            infile.seekg(0, ios::beg);      //seek to 0 bytes from the begin. of the file
                                            //is this doing what i want it to do?
                    
            while(!infile.eof())
            {
                getline(infile, dummy, '\n');
                cout << "inside while loop, read into dummy: " << dummy << endl;
                system("pause");
                //int dummySize = dummy.size();       //compute size of string
                pipePos = dummy.find('|', 0);       //find pipe starting at position 0
                if(pipePos == 0)                    //This is definitely a reference
                {
                    aRef = dummy.substr(1, dummy.size());   //take the rest of string as a ref
                    if(aRef == refs[verseChoice-1])         //if ref. found in file == chosen ref.
                    {
                        cout << "\n\nYou chose: " << aRef << "\n\n";
                        for(int b=0; b<5; b++)
                        {
                            getline(infile, dummy, '\n');
                            cout << dummy << endl;
                        }
                    }
                    else
                        cout << "Could not find the reference you chose." << endl;
                        
                    cout << "\n\n";
                    system("pause");
                }  //end if
            }  //end while
                 
        infile.close();
        
        system("pause");
    }

    Thanks for any help you can throw my way.

  5. #5
    Registered User
    Join Date
    Mar 2002
    Posts
    1,595
    if the stream has not been used yet then the pointer to read the file is automatically at the beginning of the file. My understanding is that once you have read part of the file you can reset the pointer to read the file to the beginning again by using the seekg(0, ios::beg); command. However, if you reach the end of the file before you want to reset the pointer to read the file back to the beginning, then the stream needs to be cleared with the streamName.clear(); command before you can reset the pointer to read the file back to the beginning. This is because finding EOF (which is the terminating condition for your while loop) causes the stream to fail and a failed stream cannot be reset (or reused) until it is cleared.

  6. #6
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Once you get to a point where infile.eof() is true, you need to reset some flags within the infile stream by calling infile.clear(). This must be done prior to the infile.seekg(0,ios::beg) call.

    You can probably use the other version of the getline function, for example:
    Code:
    getline(infile,dummy);
    As long as your lines in the text file have newline characters at the end of them this will do fine.

    The infile.close() is not really needed but it's ok to have it there. Once the function is over, the destructor will automatically be called which will close the stream by itself.

    An easier way to do this might be to consider an STL container class to store the data, perhaps a map<int,vector<string> > container, i.e:
    Code:
    #include <vector>
    #include <map>
    #include <string>
    #include <fstream>
    #include <iostream>
    #include <iterator>    // For ostream_iterator
    #include <algorithm>   // For copy
    using namespace std;
    
    void SearchForVerse()
    {
        map<int,vector<string> > Verses;
        map<int,vector<string> >::iterator itVerses;
        vector<string> aVerse;
        ifstream infile("verses.txt");
        string temp;
        unsigned int verseChoice, i = 0;
    
        // Read input file, store all verses into map.
    
        getline(infile,temp);
        while( !infile.eof() )
        {
            if( temp.length() != 0 )
            {
                if( temp[0] == '|'  )
                {
                    if( i > 0 )
                    {
                        Verses[i] = aVerse;
                        aVerse.clear();
                    }
                    aVerse.push_back(temp);
                    ++i;
                }
                else aVerse.push_back(temp);
            }
            getline(infile,temp);
        }
        Verses[i] = aVerse; // [edit] added this[/edit]
    
        // Show all entries and get users choice.
    
        cout << "Here are the references for the verses stored in verses.txt...\n\n";
        for( itVerses = Verses.begin(); itVerses != Verses.end(); ++itVerses )
            cout << itVerses->first << ". " << itVerses->second[0] << endl;
        cout << "Choose a verse to display: ";
        cin >> verseChoice;
    
        // Output selected verse to screen.
    
        if( verseChoice <= Verses.size() && verseChoice != 0 )
        {
            ostream_iterator<string> osit(cout,"\n");
            copy(Verses[verseChoice].begin(),Verses[verseChoice].end(),osit);
        }
    
    }
    Last edited by hk_mp5kpdw; 05-04-2004 at 08:15 AM.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  7. #7
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    Question about deleting...

    Thank you for the advice about vectors & maps. Maps are really powerful if you know how to use them. I didn't really understand this chunk of code that you used to display the contents of the map/vector:

    Code:
    if( verseChoice <= Verses.size() && verseChoice != 0 )
        {
            ostream_iterator<string> osit(cout,"\n");
            copy(Verses[verseChoice].begin(),Verses[verseChoice].end(),osit);
        }
    My C++ books are too elementary to have more advance STL stuff like this. I can only guess about the declaration of the ostream_iterator and the copy line. Declare an ostream_iterator that iterates through strings called "osit" that displays the contents of the output stream as it iterates and uses the newline char as the delimiter? Copy from the beginning of the chosen vector within the map to the end of the vector . . . to osit, an ostream_iterator which is set up to display it's contents line by line. How'm I doin'?

    I was wondering, how to delete a vector from the map and rewrite the text file with the new map? I've been trying to figure it out by myself but I keep scratching my head trying to figure out what next.

    Oop, 1 other thing...I'm trying to figure out how to get rid of the pipe after the search when I display the verse that was found.

    Thanks for all your help.

    Swaine777
    Last edited by Swaine777; 05-20-2004 at 11:31 PM.

  8. #8
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by Swaine777
    My C++ books are too elementary to have more advance STL stuff like this. I can only guess about the declaration of the ostream_iterator and the copy line. Declare an ostream_iterator that iterates through strings called "osit" that displays the contents of the output stream as it iterates and uses the newline char as the delimiter? Copy from the beginning of the chosen vector within the map to the end of the vector . . . to osit, an ostream_iterator which is set up to display it's contents line by line. How'm I doin'?
    That's basically what it's doing... yes.

    I was wondering, how to delete a vector from the map and rewrite the text file with the new map? I've been trying to figure it out by myself but I keep scratching my head trying to figure out what next.
    The map container comes equipped with an erase member function. Though there are different versions of this function, one that should interest you is the one that takes as a parameter the key value that you wish to find and erase from the map. It returns the number of elements removed, which in the case of a map should always be either 0 or 1. For the example we are working with, if we wanted to erase the second verse from the map we could say simply:

    Code:
    Verses.erase(2);
    However, if we did that and then tried to redisplay the list of choices immediately after the call to erase, we would then get:

    Code:
    Here are the references for the verses stored in verses.txt...
    
    1. Romans 3:23
    3. Romans 1:21
    Note that our numbering is now off a little. I would recommend you write the new map contents to the file and reload it before displaying and asking for the users choice. Also, a better way than what I had before to validate the users choice for verse might be to do this:

    Code:
    if( Verses.find(verseChoice) != Verses.end() )
    {
        ostream_iterator<string> osit(cout,"\n");
        copy(Verses[verseChoice].begin(),Verses[verseChoice].end(),osit);
    }
    Writing the new data in the map container to your file is a simple matter of using an iterator to loop over the whole map. Within that loop, you then need another iterator in a loop to output all the strings for a particular verse (remembering to also output a pipe symbol for the first line fo each new verse).

    Quote Originally Posted by Swaine777
    Oop, 1 other thing...I'm trying to figure out how to get rid of the pipe after the search when I display the verse that was found.
    Make following change in red
    Code:
    if( temp[0] == '|'  )
    {
        if( i > 0 )
        {
            Verses[i] = aVerse;
            aVerse.clear();
        }
        aVerse.push_back(temp.substr(1));
        ++i;
    }
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  9. #9
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    Smile Yes!!! Thank U!!!!

    I appreciate it so much! I was just reading a map tutorial today. It was good but it didn't have an example of find() and erase().

    How'd U learn all that stuff about maps anyway? Can you remember which book or class you took?

    Gratefully,

    Swaine777

  10. #10
    Registered User Russell's Avatar
    Join Date
    May 2004
    Posts
    71
    I posted a link to an excellent STL book in the following thread: http://cboard.cprogramming.com/showthread.php?t=53278

  11. #11
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by Swaine777
    I appreciate it so much! I was just reading a map tutorial today. It was good but it didn't have an example of find() and erase().

    How'd U learn all that stuff about maps anyway? Can you remember which book or class you took?

    Gratefully,

    Swaine777
    A good book about the whole STL area of programming is Nicolai Josuttis' The C++ Standard Library - A Tutorial and Reference. I carry that book around with me everywhere. It's not a beginners book but it is a must have.
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

  12. #12
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    thanks

    Thanks for the book idea. I'll be looking for some good C++ books when I go back to the States.

  13. #13
    Registered User
    Join Date
    Mar 2003
    Posts
    30

    more questions about this proggie

    Hi again,

    I've been working on implementing the suggestions you made for my program concerning maps and vectors and I realized that I don't know how to access the elements of the vectors within the map...

    Code:
    cout << "Rewriting verse file...\n\n";
        
        int count = 0;
        
        for(itVerses = Verses.begin(), itVerses != Verses.end(), itVerses++)
        {
            for(vit = Verses[count].begin(), vit != Verses[count].end(), vit++)
            {
                if(Verses[count]      //scratch head here
    I made an iterator for the vector as you said and hopefully I'm using it correctly in the for loop. I know you can get a vector's element by going "aVerse[i]" but how do you do that for a vector within a map? Verses[count].aVerse[count]?????

    Also,

    I'm assuming that if I have a function that loads the map, that when I leave the scope of the function, the map is gone too. Is that right? Or maybe since this is a global function it's still there? What's the best way to make a LoadMap() function that is accessable by many other functions? Should I have the LoadMap() function return a reference to the map?

    If I want to have a function that loads the map and then displays the contents of the map that all other
    functions can access (i.e. LoadVerses() and DeleteVerse()) does that mean that I have to make a class? I've tried to learn classes a number of times and I it's just not getting through my head. I need to practice working with classes, accessing member variables and member functions of classes, inheritance, polymorphism, all that stuff.

    Thanks again for all your help.

  14. #14
    Registered User hk_mp5kpdw's Avatar
    Join Date
    Jan 2002
    Location
    Northern Virginia/Washington DC Metropolitan Area
    Posts
    3,817
    Quote Originally Posted by Swaine777
    Hi again,

    I've been working on implementing the suggestions you made for my program concerning maps and vectors and I realized that I don't know how to access the elements of the vectors within the map...

    Code:

    cout << "Rewriting verse file...\n\n";

    int count = 0;

    for(itVerses = Verses.begin(), itVerses != Verses.end(), itVerses++)
    {
    for(vit = Verses[count].begin(), vit != Verses[count].end(), vit++)
    {
    if(Verses[count] //scratch head here


    I made an iterator for the vector as you said and hopefully I'm using it correctly in the for loop. I know you can get a vector's element by going "aVerse[i]" but how do you do that for a vector within a map? Verses[count].aVerse[count]?????
    Code to iterate through the map and vector elements should look something like this:

    Code:
    map<int,vector<string> >::iterator itVerses;
    vector<string>::iterator vit;
    
    // Iterate through the map values...
    
    for( itVerses = Verses.begin(); itVerses != Verses.end(); ++itVerses )
    {
        // Now iterate throught the particular string vector containing the single verse.
        // itVerses as a map iterator has some important members, first and second,
        // itVerses->first is the key and itVerses->second is the value which
        // in this case is the vector<string> container that we stored in the map
        // Therefore, itVerses->second.begin() returns a vector<string>
        // iterator to the beginning of the particular vector element, i.e. string
        // that we are dealing with
    
        for( vit = itVerses->second.begin(); vit != itVerses->second.end(); ++vit )
        {
            // Do something with the individual string we are looking at
            // Such as write it to the screen...
    
            cout << *vit << endl;
        }
    
    }
    The above code will output the entire contents of the map, all of the verses to the screen. If you are rewritting the map to a file in order to store a modified set of verses, then you will need to remember to add that pipe symbol to the output for the first string element of the vector. In the above code, this could be accomplished by inserting the necessary code before the inner for loop.

    Quote Originally Posted by Swaine777
    Also,

    I'm assuming that if I have a function that loads the map, that when I leave the scope of the function, the map is gone too. Is that right? Or maybe since this is a global function it's still there? What's the best way to make a LoadMap() function that is accessable by many other functions? Should I have the LoadMap() function return a reference to the map?

    If I want to have a function that loads the map and then displays the contents of the map that all other
    functions can access (i.e. LoadVerses() and DeleteVerse()) does that mean that I have to make a class? I've tried to learn classes a number of times and I it's just not getting through my head. I need to practice working with classes, accessing member variables and member functions of classes, inheritance, polymorphism, all that stuff.
    You would do well to make individual functions to load, display, write, and delete elements from the map. You should pass the map as a reference parameter to your functions so that they can access and modify it. Then you can have your map declaration in main for instance and pass it to all of your functions which will perform all your necessary operations:

    Code:
    LoadVersesFromFile(map<int,vector<string> >& Verses);
    DeleteSelectedVerse(map<int,vector<string> >& Verses);
    WriteVersesToFile(map<int,vector<string> >& Verses);
    DisplayUsersVerse(map<int,vector<string> >& Verses);
    
    int main()
    {
        map<int,vector<string> > Verses;
    
        LoadVersesFromFile( Verses );
    
        DisplayUsersVerse( Verses );
    
        DeleteSelectedVerse( Verses );
    
        WriteVersesToFile( Verses );
    
        return 0;
    }
    "Owners of dogs will have noticed that, if you provide them with food and water and shelter and affection, they will think you are god. Whereas owners of cats are compelled to realize that, if you provide them with food and water and shelter and affection, they draw the conclusion that they are gods."
    -Christopher Hitchens

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Formatting a text file...
    By dagorsul in forum C Programming
    Replies: 12
    Last Post: 05-02-2008, 03:53 AM
  2. Formatting the contents of a text file
    By dagorsul in forum C++ Programming
    Replies: 2
    Last Post: 04-29-2008, 12:36 PM
  3. struct question
    By caduardo21 in forum Windows Programming
    Replies: 5
    Last Post: 01-31-2005, 04:49 PM
  4. checking values in a text file
    By darfader in forum C Programming
    Replies: 2
    Last Post: 09-24-2003, 02:13 AM
  5. what does this mean to you?
    By pkananen in forum C++ Programming
    Replies: 8
    Last Post: 02-04-2002, 03:58 PM