1. Limited time only! Sign up for a free 30min personal tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Creating ifstream variables at run time in C++?

  1. Sep 14, 2012 #1
    How do you make a number of input file streams, one for each input file so that can copy/append the contents of these files to one output file? The number of input files is only known at run time and varies from run to run of the program. The input file names are first stored in a linked list. Would you use RTTI?

    Code (Text):
     int main()
    ...
    charList *ptrFile;
    charList filesin;
    ptrFile = &filesin;  // is the linked list object
    ifstream ifs;

    ofstream ofs;

    ...

    for (int i = 0; i <  ptrFile->getCount(); i++) {
      ifs.open(ptr->getValue(), ios::in);
      ...
      copyFile(ifs, ofs); // copy contents of an input file to the output file
      ifs.close():
      ptrFile = ptrFile->getNextEntry();
    }
    ofs.close();
    return 0;
    }
    where: getCount(), getValue() and getNextEntry() are member functions of charList, a linked list of input file names. Any suggestions would be appreciated.
     
  2. jcsd
  3. Sep 14, 2012 #2

    chiro

    User Avatar
    Science Advisor

    Hey John O' Meara.

    I don't think you need any kind of C++ specific functionality for this exercise.

    If you are just opening a bunch of files and appending the contents of all files to an output file in the order that they are given, then a loop similar to what you have written should be more than sufficient.

    Whatever interface you use for files whether it be the standard file library (fopen, fclose, etc), the Windows Functionality (OpenFile, etc) or some other wrapper library with that functionality, the only thing you will need to remember for each iteration of the loop is a file handle, and at most some kind of temporary buffer to grab data from one file and then throw it into another.

    You may however, have to do multiple reads of the input file if the temporary buffer you are using is too small, but you can create a simple function to do a loop to do that (and there is probably a function to do it for you but it's pretty straight forward).

    Is there any other kind of purpose you are thinking of including (are you thinking about adding new functionality or extending the code in some way)?
     
  4. Sep 15, 2012 #3
    Hi chiro, thanks for replying.

    As the code I have written stands, it refuses to increment i in the for loop and it only adds the first file entered to the output file; so I was thinking that I needed a seperate ifstream object for each input file. and so I thought that the code was wrong. If I add the following piece of code in the proper place to the code I have already given
    Code (Text):
     if (!ifs.good()) {
      cout << "A file error occured.\n"; }
    g++ gives the above error after appending the first input file to the output file; while a C++ compiler runs without giving this error but still refuses like I said to increment to loop variable i. I don't entend to add any more functionality to this code. As you say I just want to open a bunch of files and append the contents of all files to one output file. I might find this routine handy for future use in something else, though at the moment I have nothing particular in mind. Thanks again.
     
  5. Sep 15, 2012 #4

    chiro

    User Avatar
    Science Advisor

    Ohh I see what you are getting at.

    You need to look at if your linked list object has a standard iterator, and if you are using a template class, then look at if that has an iterator (things like linked list in C++ usually do) and if they do, see what it is and its implementation.
     
  6. Sep 15, 2012 #5
    This is the linked list:
    Code (Text):

    class charList {
     char value[80];
     charList *nextEntry;
     int count;
    public:
      charList() { count = 0; }
      charList(char *v, charList *next) : nextEntry(next), count(0)
      { strcpy(value, v);  }

       char *getValue() { return value; }
       charList *getNextEntry() { return nextEntry; }
       int getCount() { return count; }
       void incrCount() { count++; }
       void addToEndM(char *str);
    };

     void charList::addToEndM(char *str)
     {
      if (nextEntry !=NULL)
         nextEntry->addToEndM(str);
       else
          nextEntry = new charList(str, NULL);
     }

     istream& operator>>(istream& is, charList *&cl)
    {
       charList *cp = NULL;
       char ch[80];

        cin >> ch;
        while (ch[0] != '!') {
          if (cp != NULL) {
            cp->addToEndM(ch);
           else {
              cp = new charList(ch, cp);
              cp->incrCount();
           }
           cout << "Enter another file to copy: ";
           cin >> ch;
           cp->incrCount();
         }
         cl = cp;
         return is;
      }
    As you can see I am not using templates or iterators, just basic C-strings etc.
     
  7. Sep 15, 2012 #6

    chiro

    User Avatar
    Science Advisor

    I have a recommendation for you: lots of experienced programmers would look at that and go absolutely ape if they say that kind of code, but I'm going to just make a recommendation without getting too anal.

    The recommendation I have is that you implement a set of routines for an iterator: basically a routine that signals to start an iteration, and a routine that returns the next object that does an internal increment (which returns a null pointer if nothing is left).

    This is the absolute basics of an iterator. It's good design to have the iterator separate from the class, but it would be very straight-forward to just add these routines to your linked list class and add an extra variable that corresponds to the iterator.

    You might wonder what the point of this is and the answer is simple: if you want to iterate through things and have the possibility that the list is changed somehow (either by something within the iteration loop itself or through some sub function in call-stack, or through multi-threaded environments) then you want the iterator to act correctly when all this happens.

    At the very least, just add a routine that initializes the iterator and then increments a separate iterator variable to go through the list and return the pointer to the next object with doing the right increment.

    What you do this setup is that you setup a while loop (so a while loop as opposed to a do). Something like this:

    Code (Text):

    LinkedListClass* class = whatever; // Assuming whatever is valid
    whatever->InitializeIterator();
    ObjectType* objectInstance = NULL;

    // Method stores the value of the object in the pointer passed and returns
    // a non-zero return if OK and zero if not.
    while(whatever->ReturnNextIteratorObject(&objectInstance))
    {
       // Do stuff blah blah with objectInstance
    };
     
    I'd recommend that if you are going to be using these kinds of container and template classes that you develop a separate iterator object that allows you to have an interface for iteration: this way you can keep the interface and if you need to change what happens behind the scenes due to changing environments, then you can keep the interfaces without having to change all the code that calls these interfaces.

    You get some new programmers that think interfaces are over-kill, but one of the reasons why you want to know what the interface is has to do with when you get into development for a long time and then suddenly realize you need to change a core thing and you nearly lose it if you haven't used the right interfaces (it's easy to change what happens what is underlying the interfaces, but it's a pain to create new ones that are significantly different in what functionality they provide especially if they require major changes).
     
  8. Sep 15, 2012 #7
    Thank you for your recommendations and patience. I have an old book on: "Programming with class A C++ Introduction to Computer science" that I only got around to this year looking at, I guess it is out of date, though I must say that I have found it interesting, but it doesn't do iterators and only mentions templates in an appendix; so the given problem implied that it could be solved without containers, templates or iterators, I would think? It is only for myself that I am doing this computer programming, It will ever only be a hobby with me. Thank you again.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook




Similar Discussions: Creating ifstream variables at run time in C++?
Loading...