30

I am trying to read each line of a textfile which each line contains one word and put those words into a vector. How would i go about doing that?

This is my new code: I think there is still something wrong with it.

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

int main()
{
    std::string line;
    vector<string> DataArray;
    vector<string> QueryArray;
    ifstream myfile("OHenry.txt");
    ifstream qfile("queries.txt");

    if(!myfile) //Always test the file open.
    {
        cout<<"Error opening output file"<<endl;
        system("pause");
        return -1;
    }
    while (std::getline(qfile, line))
    {
        QueryArray.push_back(line);
    }
    if(!qfile) //Always test the file open.
    {
        cout<<"Error opening output file"<<endl;
        system("pause");
        return -1;
    }

    while (std::getline(qfile, line))
    {
        QueryArray.push_back(line);
    }

    cout<<QueryArray[0]<<endl;
    cout<<DataArray[0]<<endl;

}
user
  • 86,916
  • 18
  • 197
  • 190
user977154
  • 1,045
  • 4
  • 19
  • 39

4 Answers4

39

Simplest form:

std::string line;
std::vector<std::string> myLines;
while (std::getline(myfile, line))
{
   myLines.push_back(line);
}

No need for crazy c thingies :)

Edit:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

int main()

{
    std::string line;
    std::vector<std::string> DataArray;
    std::vector<std::string> QueryArray;
    std::ifstream myfile("OHenry.txt");
    std::ifstream qfile("queries.txt");

    if(!myfile) //Always test the file open.
    {
        std::cout<<"Error opening output file"<< std::endl;
        system("pause");
        return -1;
    }
    while (std::getline(myfile, line))
    {
        DataArray.push_back(line);
    }

    if(!qfile) //Always test the file open.
    {
        std::cout<<"Error opening output file"<<std::endl;
        system("pause");
        return -1;
    }

    while (std::getline(qfile, line))
    {
        QueryArray.push_back(line);
    }

    std::cout<<QueryArray[20]<<std::endl;
    std::cout<<DataArray[12]<<std::endl;
    return 0;
}

Keyword using is illegal C++! Never use it. OK? Good. Now compare what I wrote with what you wrote and try to find out the differences. If you still have questions come back.

FailedDev
  • 26,680
  • 9
  • 53
  • 73
  • i fixed the code in my post, what am i doing wrong now? because i need to work with two different text files. Thank you so much for the help by the way. – user977154 Dec 03 '11 at 03:15
  • @user977154 You don't need the outer while loop. Remove it! In both cases. Also are you sure there exist 12 and 20 lines in your vectors? – FailedDev Dec 03 '11 at 03:19
  • Yes i am positive there are more than 20 filled lines in my test files. And i keep getting error saying error opening output file – user977154 Dec 03 '11 at 03:25
  • 1
    Waitaminute. I know this is a old post - but this is dangerous. In what way is the keyword 'using' ILLEGAL in C++? Using was introduced into the language together with namespaces. "using std::cout" is perfectly valid. "using std" is perfectly valid, albeit bad practice. – gamers2000 Apr 01 '13 at 13:43
  • 1
    @gamers2000 Was being sarcastic. `int * aPtr = NULL; *aPtr = 5; // is also perfectly valid but should be considered illegal...` – FailedDev Apr 01 '13 at 22:31
  • @void.pointer Thanks for clarifying this, after me pointing it out. – FailedDev Feb 18 '15 at 21:24
38

@FailedDev did, indeed, list the simplest form. As an alternative, here is how I often code that loop:

std::vector<std::string> myLines;
std::copy(std::istream_iterator<std::string>(myfile),
          std::istream_iterator<std::string>(),
          std::back_inserter(myLines));

The entire program might look like this:

// Avoid "using namespace std;" at all costs. Prefer typing out "std::"
// in front of each identifier, but "using std::NAME" isn't (very) dangerous.
#include <iostream>
using std::cout;
using std::cin;
#include <fstream>
using std::ifstream;
#include <string>
using std::string;
#include <vector>
using std::vector;
#include <iterator>
using std::istream_iterator;
#include <algorithm>
using std::copy;

int main()
{

    // Store the words from the two files into these two vectors
    vector<string> DataArray;
    vector<string> QueryArray;

    // Create two input streams, opening the named files in the process.
    // You only need to check for failure if you want to distinguish
    // between "no file" and "empty file". In this example, the two
    // situations are equivalent.
    ifstream myfile("OHenry.txt"); 
    ifstream qfile("queries.txt");

    // std::copy(InputIt first, InputIt last, OutputIt out) copies all
    //   of the data in the range [first, last) to the output iterator "out"
    // istream_iterator() is an input iterator that reads items from the
    //   named file stream
    // back_inserter() returns an interator that performs "push_back"
    //   on the named vector.
    copy(istream_iterator<string>(myfile),
         istream_iterator<string>(),
         back_inserter(DataArray));
    copy(istream_iterator<string>(qfile),
         istream_iterator<string>(),
         back_inserter(QueryArray));

    try {
        // use ".at()" and catch the resulting exception if there is any
        // chance that the index is bogus. Since we are reading external files,
        // there is every chance that the index is bogus.
        cout<<QueryArray.at(20)<<"\n";
        cout<<DataArray.at(12)<<"\n";
    } catch(...) {
        // deal with error here. Maybe:
        //   the input file doesn't exist
        //   the ifstream creation failed for some other reason
        //   the string reads didn't work
        cout << "Data Unavailable\n";
    }
}
Robᵩ
  • 163,533
  • 20
  • 239
  • 308
26

Simplest version:

std::vector<std::string> lines;
for (std::string line; std::getline( ifs, line ); /**/ )
   lines.push_back( line );

I'm omitting the includes and other gunk. My version is almost the same as FailedDev's but by using a 'for' loop I put the declaration of 'line' in the loop. This is not just a trick to reduce the line count. Doing this reduces the scope of line -- it disappears after the for loop. All variables should have the smallest scope possible, so therefore this is better. For loops are awesome.

Bruce Dawson
  • 261
  • 3
  • 2
  • Excellent. It's even cleaner with `using namespace std;` so all the `std::` can be removed. The 'ifs' declaration is missing, declared like: `ifstream ifs(textFilePath, ios::in);` – Brent Faust Jan 30 '15 at 00:10
  • 1
    Less scope for ifs: `for(auto [line, ifs] = std::make_tuple("", std::ifstream(log_filename)); std::getline(ifs, line);) lines.push_back(line);` – mheyman May 17 '20 at 19:01
1

A short version for C++11 and above. The vector is constructed directly from the file contents:

ifstream qfile("queries.txt");
vector<string> lines {
    istream_iterator<string>(qfile),
    istream_iterator<string>()
};

Note that this code will only work if the input file is in the format described by the OP, i.e. "each line contains one word". Or if you set special locale via qfile.imbue(), as mheyman kindly pointed out.

Alexei Khlebnikov
  • 2,126
  • 1
  • 21
  • 21
  • 1
    This breaks *queries.txt* on any whitespace, you would have to `qfile.imbue()` with a locale that only uses newline as whitespace for it to work for the OP. – mheyman Jan 06 '21 at 16:44
  • True, and the accepted answer has the same limitation. In our particular case the code should work though, because the OP stated that the format of his input file is "each line contains one word". I have added this info to the answer. – Alexei Khlebnikov Jan 08 '21 at 09:52