Reading from text file or stdin
Asked Answered
N

4

7

I have a program that basically reads a text file and counts the number of occurrences of each word on each line. Everything works properly when reading from a text file using an ifstream, however, if a file name is not entered on the command line, I need to read from stdin instead.

I use the following to open and read in the file currently:

map<string, map<int,int>,compare> tokens;
ifstream text;
string line;
int count = 1;

if (argc > 1){
    try{
        text.open(argv[1]);
    }
    catch (runtime_error& x){
        cerr << x.what() << '\n';
    }

    // Read file one line at a time, replacing non-desired char's with spaces
    while (getline(text, line)){
        replace_if(line.begin(), line.end(), my_predicate, ' ');

        istringstream iss(line);    
        // Parse line on white space, storing values into tokens map
        while (iss >> line){                
            ++tokens[line][count];
        }
        ++count;
    }
}

else{
while (cin) {
    getline(cin, line);
    replace_if(line.begin(), line.end(), my_predicate, ' ');

    istringstream iss(line);
    // Parse line on white space, storing values into tokens map
    while (iss >> line){
        ++tokens[line][count];
    }
    ++count;
}

Is there a way to assign cin to an ifstream and simply add an else statement if argc > 1 fails, using the same code afterwards instead of duplicating like this? I haven't been able to find a way to do this.

Notorious answered 14/4, 2014 at 0:45 Comment(1)
I suggest you get the C++11 standard plus minor editorial changes.Pharmaceutical
H
12

Make the reading part a function of its own. Pass either an ifstream or cin to it.

void readData(std::istream& in)
{
   // Do the necessary work to read the data.
}

int main(int argc, char** argv)
{
   if ( argc > 1 )
   {
      // The input file has been passed in the command line.
      // Read the data from it.
      std::ifstream ifile(argv[1]);
      if ( ifile )
      {
         readData(ifile);
      }
      else
      {
         // Deal with error condition
      }
   }
   else
   {
      // No input file has been passed in the command line.
      // Read the data from stdin (std::cin).
      readData(std::cin);
   }

   // Do the needful to process the data.
}
Haaf answered 14/4, 2014 at 0:53 Comment(0)
P
1

You cannot assign cin to an ifstream.
But you could reopen cin to some file.

Anyway, the better method would be modularising your code and just using a std::istream&.

Pharmaceutical answered 14/4, 2014 at 0:58 Comment(0)
L
1

I just put a easy way to let the program read file if given else use stdin, and close it properly.

#include <fstream>
#include <iostream>
#include <memory>
#include <string>

int main(int argc, char* argv[]) {
    auto fp_deletor = [](std::istream* is_ptr) {
        if (is_ptr && is_ptr != &std::cin) {
            static_cast<std::ifstream*>(is_ptr)->close();
            delete is_ptr;
            std::cerr << "destroy fp.\n"; 
        }
    };

    std::unique_ptr<std::istream, decltype(fp_deletor)> is_ptr{nullptr, fp_deletor};
    if (argc > 2) {
        std::cerr << "usage: " << argv[0] << "[input-file]";
        return -1;
    } else if (argc == 1) {
        std::cerr << "using stdin as input.\n";
        is_ptr.reset(&std::cin); 
    } else {
        is_ptr.reset(new std::ifstream(argv[1]));
    }

    std::string line;
    while (std::getline(*is_ptr, line)) {
        // your logic....
    }

    // just return, unique_ptr manage the istream
    return 0;
}

Ladybird answered 23/12, 2019 at 12:14 Comment(0)
C
0

Try and assign either the file stream or cin to an istream pointer. No duplication of code.

ifstream fin;
fin.open(inFilename);
istream* inPtr = (fin.good() ? &fin : &cin);
 
while (*inPtr) {
    getline(*inPtr, line);
    replace_if(line.begin(), line.end(), my_predicate, ' ');

    istringstream iss(line);
    // Parse line on white space, storing values into tokens map
    while (iss >> line){
        ++tokens[line][count];
    }
    ++count;
}
Capillary answered 1/9 at 14:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.