1

I have written a code to read from a array of file in c which is something like below and it works fine.

I am trying to replicate it in C++ and use ifstream for array of files and trying to read one line from a file a time like I am doing in C. However with ifstream I am unable to move ahead.

I have ifstream files[] pointer from a function which would point me to first file

Below Code reads one line from each file at a time and keeps looping

   char *filename[] = {"mFile1.txt", "mFile2.txt", "mFile3.txt", "mFile4.txt"};
    char line[1000];
    FILE *fp[count];
    unsigned int loop_count;
    const int num_file = count;
    char **temp = filename;
    FILE *ffinal = fopen("scores.txt", "ab+");

    for (loop_count = 0; loop_count < count; loop_count++)
    {
        if ((fp[loop_count] = fopen(*temp,"r")) != NULL)
        {
           // printf("%s openend successfully \n",*temp);
        }
        else
        {
            printf("error file cannot be opened \n");
            exit(1);
        }
        temp++;
    }

    do 
    {
        for (loop_count = 0; loop_count < num_file; loop_count++)
        {
            memset(line, 0, sizeof(line));
            if (fgets(line, sizeof(line), fp[loop_count]) != NULL)
            {

/* --- Code in C++ where I get stuck with ifstream and getline */ it errors out with getline saying too few arguments

#include <cstdlib>
#include <fstream>
#include <iostream>
#include <new>
#include <sstream>
#include <string>

using namespace std;

ifstream *OpenFiles(char * const fileNames[], size_t count);

int main (void)
{
    char line[1000];
    char * const fileNames[] = {"abc.txt", "def.txt", "ghi.txt"};
    ifstream *pifstream = OpenFiles(fileNames, 3);

    for (int i = 0; i < 3; i++)
    {
        getline(pifstream[i], line);
    }

    return 0;
}

ifstream *OpenFiles(char * const fileNames[], size_t count)
{
    ifstream *pifstream = new (nothrow) ifstream[count];
    ifstream *preturn;
    preturn = pifstream;
    if (pifstream == NULL)
    {
        cerr << "error opening the file";   
    }


    for (int elem = 0; elem < count; elem++)
    {
        pifstream[elem].open(fileNames[elem]);
        if (!pifstream)
        {
            cerr << "existing with error ";
            exit(1);
        }
    }

    return preturn;
}
oneday
  • 537
  • 1
  • 5
  • 25
  • "I am trying to replicate it in C++ and use ifstream... " - How about you also post that "try" . This looks exclusively like the C code, – WhozCraig Aug 27 '15 at 00:04
  • have a look at http://stackoverflow.com/questions/7868936/read-file-line-by-line , using the search function here(or via google) saves asking duplicate questions – lxx Aug 27 '15 at 00:04
  • Also I'd suggest using c++ rather than c (and just compiling it with a c++ compiler) and c++ strings as they will make your life much easier – lxx Aug 27 '15 at 00:05
  • @lxx : I did spend time doing that but wasnt able to figure out - let me spend more time – oneday Aug 27 '15 at 00:18
  • Why do you need the `preturn` variable? Why don't you just `return pifstream`? – Barmar Aug 27 '15 at 00:19
  • @Barmar - no reason - was trying bunch of things and ended up posting code without clean up – oneday Aug 27 '15 at 00:20
  • If the error is on the `getline()` line, it has nothing to do with how you're opening the files. – Barmar Aug 27 '15 at 00:24
  • Not entirely sure, but [**is this**](http://pastebin.com/kVw1TUZp) what you're trying to do? – WhozCraig Aug 27 '15 at 00:24
  • 2
    Your code assumes getline() is declared differently that what's reality http://www.cplusplus.com/reference/string/string/getline/ – nos Aug 27 '15 at 00:25
  • 1
    The second argument to `getline()` should be `std::string`, not `char*`. – Barmar Aug 27 '15 at 00:26
  • In the line `if (!pifstream)`, I'm pretty sure you meant to test `pifstream[elem]`. – paddy Aug 27 '15 at 00:28
  • @WhozCraig - Thanks yes planning to achieve something like that - without using vectors - I see one of the other members also pointing that my getline() is declared differently - can you help me understand what is difference between your getline and mine ? – oneday Aug 27 '15 at 00:39
  • @nos : Thanks for the pointer I got it - !!! – oneday Aug 27 '15 at 00:41
  • @oneday If passing a hard buffer, you should be using `obj.getline(buf, buf_len)`, where `obj` is your stream reference, not the generic `std:;getline`. And I cannot encourage you strongly enough to avoid manual dynamic memory management. [RAII](https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization) - its what's for dinner. – WhozCraig Aug 27 '15 at 00:41
  • @WhozCraig : I see the error was because of char* declaration in getline instead of string – oneday Aug 27 '15 at 00:42
  • @oneday exactly. Either use a fixed buffer and change to use the objects getline member, or use a `std::string` in tandem with `std::getline`. Both have reasons to use (and not use) them, situationally dependent. You will probably be good with the latter. – WhozCraig Aug 27 '15 at 00:44

1 Answers1

3
#include <array>        // Constant size container
#include <vector>       // Dynamic size container
#include <fstream>      // File I/O
#include <stdexcept>    // Stock exceptions
#include <iostream>     // Standard I/O streams

// Program entry
int main(){
    // Like C array, but with useful member functions
    const std::array<const char*, 3> filenames{"test1.txt", "test2.txt", "test3.txt"};
    // Still empty vector of input file streams
    std::vector<std::ifstream> files;
    // Iterate through filenames, one-by-one
    for(auto filename : filenames){
        // Create input file stream in-place at end of vector
        files.emplace_back(filename);
        // Last input file stream in vector (see line above) is with error (opening failed)
        if(!files.back())
            // Throw error upwards (there's no catch, so the host, like the console, reports the exception message)
            throw std::runtime_error("Couldn't open file: " + std::string(filename));
    }
    // Line buffer
    std::string line;
    // Just loop 3 times (for lines)
    for(unsigned line_i = 0; line_i < 3; ++line_i)
        // Iterate through file streams
        for(auto& file : files)
            // Get current line from file stream (moves file pointer behind line + separator) and check stream status (if stream is EOF, the condition goes 'false' and nothing further happens)
            if(std::getline(file, line))
                // Write line number, character ':' and gotten line to standard output
                std::cout << line_i << ':' << line << std::endl;
    // Program exit status (usually 0 == OK)
    return 0;
}

Safe, fast, simple. This code requires C++11 (which shouldn't be a problem these days anymore) and hasn't any additional dependency, just STL.

Youka
  • 2,460
  • 18
  • 31
  • thanks a lot. this is part of my learning exercise - and we are not taught vectors yet - can you guide me to some way to achieve it without vectors? – oneday Aug 27 '15 at 00:34
  • 1
    While this answer is probably correct and useful, it is preferred if you [include some explanation along with it](http://meta.stackexchange.com/q/114762/159034) to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. – Kevin Brown Aug 27 '15 at 00:34
  • @oneday Moment, i add comments. – Youka Aug 27 '15 at 00:37
  • @oneday You should learn C++ the right way and not C with objects (could become a bad habit, burned in your brain), so i recommend you learn the [STL](https://en.wikipedia.org/wiki/Standard_Template_Library), it's not that hard. A [vector](http://en.cppreference.com/w/cpp/container/vector) is, told simply, to use like a list & array. There aren't many members, so don't hesitate ;) – Youka Aug 27 '15 at 01:00
  • @Youka - Sure.will keep it in mind and yes soon will read and practice STL – oneday Aug 27 '15 at 01:53