How to Read a File into Vector in C++

How to read a file into vector in C++?

Your loop is wrong:

for (int i=0; i=((Main.size())-1); i++) {

Try this:

for (int i=0; i < Main.size(); i++) {

Also, a more idiomatic way of reading numbers into a vector and writing them to stdout is something along these lines:

#include <iostream>
#include <iterator>
#include <fstream>
#include <vector>
#include <algorithm> // for std::copy

int main()
{
std::ifstream is("numbers.txt");
std::istream_iterator<double> start(is), end;
std::vector<double> numbers(start, end);
std::cout << "Read " << numbers.size() << " numbers" << std::endl;

// print the numbers to stdout
std::cout << "numbers read in:\n";
std::copy(numbers.begin(), numbers.end(),
std::ostream_iterator<double>(std::cout, " "));
std::cout << std::endl;

}

although you should check the status of the ifstream for read errors.

How do you read a text file into a vector in c++?

This vector:

vector <int> list = {};

Has exactly zero members. You never try and increase its size so any access to this array will result in a bad result.

There are a couple of places you accesses this vector:

input>>list[i];

// and

cout<<list[k];

These are both invalid access to the list.

To fix the problem you can read the data into a value and then append it to the vector:

int value;
input >> value;
list.emplace_back(value); // emplace back expands the vector by one place.

But that is not your only problem:

 while (i <= count_line() && count_line() > 0){

This while statement contains to calls that open a file parse the whole file and return a count. I doubt the compiler can optimize that away so that is exceedingly expensive call to make.

Can you just read values until there are none left?

 int   value;
while(input >> value) {
list.emplace_back(value);
}

But the proper way to do this:

 #include <vector>
#include <iterator>
#include <iostream>
#include <fstream>

int main()
{
std::ifstream file("text.txt");
std::vector<int> data(std::istream_iterator<int>{file},
std::istream_iterator<int>{});

for(auto val: data) {
std::cout << val << " ";
}
std::cout << "\n";
}

Read file and input into vector

As already mentioned, std::getline and std::istringstream are good starting points.

Then you can use std::istream_iterator to create the vectors directly using the iterator overload of the std::vector constructor.

Perhaps something like this:

std::vector<std::vector<int>> read_file(std::istream& input)
{
std::vector<std::vector<int>> lines;

std::string line;
while (std::getline(input, line))
{
std::istringstream line_stream(line);

lines.emplace_back(std::istream_iterator<int>(line_stream),
std::istream_iterator<int>());
}

return lines;
}

This handles an arbitrary number of lines containing an arbitrary number of integer values.


Can be used something like this:

int main(int, char* argv[])
{
std::ifstream input(argv[1]);
auto data = read_file(input);

std::cout << "First line of data: ";
for (auto value : data[0])
{
std::cout << value << ' ';
}
std::cout << '\n';

std::cout << "Second line of data: ";
for (auto value : data[1])
{
std::cout << value << ' ';
}
std::cout << '\n';
}

Important note: The example above lacks any kind of error or range checking. It's left as an exercise for the reader.

How to read file into vector of tuple?

while (std::getline(File, name, '\t') >> a >> b)
{
data.push_back(std::tuple<std::string, int, double>(name, a, b));
}

std::getline reads up to and including a delimiter, then discards the delimiter. It defaults to the delimiter being a newline; here we make it a tab.

read integers from a file into a vector in C++

I think you should store it in a variable of type double. Seems you are doing >> to a vector, which is not valid. Consider the following code:

// open file    
ifstream inputFile("/home/shared/data4.txt");

// test file open
if (inputFile) {
double value;

// read the elements in the file into a vector
while ( inputFile >> value ) {
rainfall.push_back(value);
}

// close the file

As @legends2k points out, you don't need to use the variable count. Use rainfall.size() to retrieve the number of items in the vector.

Read from comma separated file into vector of objects

I will try to help and explain you all steps. I will first show a little bit of theory and then some easy solution, some alternative solutions and the C++ (object-oriented) approach.

So, we will go from super easy to more modern C++ solution.

Let’s start. Assume that you have a of player with some attributes. Attributes could be for example: ID Name Age Score. If you store this data in a file, it could look like:

1  Peter   23   0.98
2 Carl 24 0.75
3 Bert 26 0.88
4 Mike 24 0.95

But at some point in time, we notice that this nice and simple format will not work any longer. The reason is that formatted input functions with the extractor operator >> will stop the conversion at a white space. And this will not work for the following example:

1  Peter Paul    23   0.98
2 Carl Maria 24 0.75
3 Bert Junior 26 0.88
4 Mike Senior 24 0.95

Then the statement fileStream >> id >> name >> age >> score; will not work any longer, and everything will fail. Therefore storing data in a CSV (Comma Separated Values) format is widely chosen.

The file would then look like:

1,  Peter Paul,    23,   0.98
2, Carl Maria, 24, 0.75
3, Bert Junior, 26, 0.88
4, Mike Senior, 24, 0.95

And with that, we can clearly see, what value belongs to which attribute. But unfortunately, this will make reading more difficult. Because you do need to follow 3 steps now:

  1. Read a complete line as a std::string
  2. Split this string into substrings using the comma as a separator
  3. Convert the substrings to the required format, for example from string to number age

So, let us solve this step by step.

Reading a complete line is easy. For this we have the function std::getline. It will read a line (at text until the end of the line character ‘\n’) from a stream (from any istream, like std::cin, an std::ifstream or also from an std::istringstream) and store it in a std::string variable. Please read a description of the function in the CPP Reference here.

Now, splitting a CSV string in its parts. There are so many methods available, that it is hard to tell what is the good one. I will also show several methods later, but the most common approach is done with std::getline. (My personal favorite is the std::sregex_token_iterator, because it fits perfectly into the C++ algorithm world. But for here, it is too complex).

OK, std::getline. As you have read in the CPP reference, std::getline reads characters until it finds a delimiter. If you do not specify a delimiter, then it will read until the end of line \n. But you can also specify a different delimiter. And this we will do in our case. We will choose the delimiter ‘,’.

But, additional problem, after reading a complete line in step 1, we have this line in a std::string. And, std::getline wants to read from a stream. So, the std::getline with a comma as delimiter cannot be used with a std::string as source. Fortunately also here is a standard approach available. We will convert the std::string into a stream, by using a std::istringstream. You can simply define a variable of this type and pass the just read string as parameter to its constructor. For example:

std::istringstream iss(line);

And now we can use all iostream functions also with this “iss”. Cool. We will use std::getline with a ‘,’ delimiter and receive a substring.

The 3rd and last is unfortunately also necessary. Now we have a bunch of substrings. But we have also 3 numbers as attributes. The “ID” is an unsigned long, the “Age” is an int and the “Score” is a double, So we need to use string conversion functions to convert the substring to a number: std::stoul, std::stoi and std::stod. If the input data is always OK, then this is OK, but if we need to validate the input, then it will be more complicated. Let us assume that we have a good input.

Then, one of really many many possible examples:

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

struct Player {
unsigned long ID{};
std::string name{};
int age{};
double score{};
};

// !!! Demo. All without error checking !!!
int main() {

// Open the source CSV file
std::ifstream in("players.txt");

// Here we will store all players that we read
std::vector<Player> players{};

// We will read a complete line and store it here
std::string line{};

// Read all lines of the source CSV file
while (std::getline(in, line)) {

// Now we read a complete line into our std::string line
// Put it into a std::istringstream to be able to extract it with iostream functions
std::istringstream iss(line);

// We will use a vector to store the substrings
std::string substring{};
std::vector<std::string> substrings{};

// Now, in a loop, get the substrings from the std::istringstream
while (std::getline(iss, substring, ',')) {

// Add the substring to the std::vector
substrings.push_back(substring);
}
// Now store the data for one player in a Player struct
Player player{};
player.ID = std::stoul(substrings[0]);
player.name = substrings[1];
player.age = std::stoi(substrings[2]);
player.score = std::stod(substrings[3]);

// Add this new player to our player list
players.push_back(player);
}

// Debug output
for (const Player& p : players) {
std::cout << p.ID << "\t" << p.name << '\t' << p.age << '\t' << p.score << '\n';
}
}

You see, it is getting more complex.

If you are more experienced, then you can use also other mechanisms. But then you need to understand the difference between formatted an unformatted input and need to have little bit more practice. This is complex. (So, do not use that in the beginning):

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

struct Player {
unsigned long ID{};
std::string name{};
int age{};
double score{};
};

// !!! Demo. All without error checking !!!
int main() {

// Open the source CSV file
std::ifstream in("r:\\players.txt");

// Here we will store all players that we read
Player player{};
std::vector<Player> players{};

char comma{}; // Some dummy for reading a comma

// Read all lines of the source CSV file
while (std::getline(in >> player.ID >> comma >> std::ws, player.name, ',') >> comma >> player.age >> comma >> player.score) {

// Add this new player to our player list
players.push_back(player);
}
// Debug output
for (const Player& p : players) {
std::cout << p.ID << "\t" << p.name << '\t' << p.age << '\t' << p.score << '\n';
}
}

As said, do not use in the beginning.

But, what you should try to learn and understand is: C++ is an object oriented language. This means we do not only put the data into the Player struct, but also the methods that operate on this data.

And those are at the moment just input and output. And as you already know, input and output is done using iostream-functionality with the extractor operator >> and inserter operator <<. But, how to do this? Our Player struct is a custom type. It has no build in >> and << operator.

Fortunately, C++ is a powerful language and allows us to add such functionality easily.

The signature of the struct would then look like:

struct Player {

// The data part
unsigned long ID{};
std::string name{};
int age{};
double score{};

// The methods part
friend std::istream& operator >> (std::istream& is, Player& p);
friend std::ostream& operator << (std::ostream& os, const Player& p);
};

And, after writing the code for these operators using the above-mentioned method, we will get:

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

struct Player {

// The data part
unsigned long ID{};
std::string name{};
int age{};
double score{};

// The methods part
friend std::istream& operator >> (std::istream& is, Player& p) {
std::string line{}, substring{}; std::vector<std::string> substrings{};
std::getline(is, line);
std::istringstream iss(line);
// Read all substrings
while (std::getline(iss, substring, ','))
substrings.push_back(substring);
// Now store the data for one player in the given Player struct
Player player{};
p.ID = std::stoul(substrings[0]);
p.name = substrings[1];
p.age = std::stoi(substrings[2]);
p.score = std::stod(substrings[3]);
return is;
}
friend std::ostream& operator << (std::ostream& os, const Player& p) {
return os << p.ID << "\t" << p.name << '\t' << p.age << '\t' << p.score;
}
};

// !!! Demo. All without error checking !!!
int main() {

// Open the source CSV file
std::ifstream in("r:\\players.txt");

// Here we will store all players that we read
Player player{};
std::vector<Player> players{};

// Read all lines of the source CSV file into players
while (in >> player) {

// Add this new player to our player list
players.push_back(player);
}

// Debug output
for (const Player& p : players) {
std::cout << p << '\n';
}
}

It is simply reusing everything from what we learned above. Just put it at the right place.

We can even go one step ahead. Also the player list, the ste::vector<Player> can be wrapped in a class and amended with iostream-functionality.

By knowing all of the above, this will be really simple now. See:

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

struct Player {

// The data part
unsigned long ID{};
std::string name{};
int age{};
double score{};

// The methods part
friend std::istream& operator >> (std::istream& is, Player& p) {
char comma{}; // Some dummy for reading a comma
return std::getline(is >> p.ID >> comma >> std::ws, p.name, ',') >> comma >> p.age >> comma >> p.score;
}
friend std::ostream& operator << (std::ostream& os, const Player& p) {
return os << p.ID << "\t" << p.name << '\t' << p.age << '\t' << p.score;
}
};

struct Players {

// The data part
std::vector<Player> players{};

// The methods part
friend std::istream& operator >> (std::istream& is, Players& ps) {
Player player{};
while (is >> player) ps.players.push_back(player);
return is;
}
friend std::ostream& operator << (std::ostream& os, const Players& ps) {
for (const Player& p : ps.players) os << p << '\n';
return os;
}
};

// !!! Demo. All without error checking !!!
int main() {

// Open the source CSV file
std::ifstream in("players.txt");

// Here we will store all players that we read
Players players{};

// Read the complete CSV file and store everything in the players list at the correct place
in >> players;

// Debug output of complete players data. Ultra short.
std::cout << players;
}

I would be happy, if you could see the simple and yet powerful solution.

At the very end, as promised. Some further methods to split a string into substrings:

Splitting a string into tokens is a very old task. There are many many solutions available. All have different properties. Some are difficult to understand, some are hard to develop, some are more complex, slower or faster or more flexible or not.

Alternatives

  1. Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
  2. Using old style std::strtok function. Maybe unsafe. Maybe should not be used any longer
  3. std::getline. Most used implementation. But actually a "misuse" and not so flexible
  4. Using dedicated modern function, specifically developed for this purpose, most flexible and good fitting into the STL environment and algortithm landscape. But slower.

Please see 4 examples in one piece of code.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <regex>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <forward_list>
#include <deque>

using Container = std::vector<std::string>;
std::regex delimiter{ "," };

int main() {

// Some function to print the contents of an STL container
auto print = [](const auto& container) -> void { std::copy(container.begin(), container.end(),
std::ostream_iterator<std::decay<decltype(*container.begin())>::type>(std::cout, " ")); std::cout << '\n'; };

// Example 1: Handcrafted -------------------------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};

// Search for comma, then take the part and add to the result
for (size_t i{ 0U }, startpos{ 0U }; i <= stringToSplit.size(); ++i) {

// So, if there is a comma or the end of the string
if ((stringToSplit[i] == ',') || (i == (stringToSplit.size()))) {

// Copy substring
c.push_back(stringToSplit.substr(startpos, i - startpos));
startpos = i + 1;
}
}
print(c);
}

// Example 2: Using very old strtok function ----------------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};

// Split string into parts in a simple for loop
#pragma warning(suppress : 4996)
for (char* token = std::strtok(const_cast<char*>(stringToSplit.data()), ","); token != nullptr; token = std::strtok(nullptr, ",")) {
c.push_back(token);
}

print(c);
}

// Example 3: Very often used std::getline with additional istringstream ------------------------------------------------
{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };
Container c{};

// Put string in an std::istringstream
std::istringstream iss{ stringToSplit };

// Extract string parts in simple for loop
for (std::string part{}; std::getline(iss, part, ','); c.push_back(part))
;

print(c);
}

// Example 4: Most flexible iterator solution ------------------------------------------------

{
// Our string that we want to split
std::string stringToSplit{ "aaa,bbb,ccc,ddd" };

Container c(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});
//
// Everything done already with range constructor. No additional code needed.
//

print(c);

// Works also with other containers in the same way
std::forward_list<std::string> c2(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {});

print(c2);

// And works with algorithms
std::deque<std::string> c3{};
std::copy(std::sregex_token_iterator(stringToSplit.begin(), stringToSplit.end(), delimiter, -1), {}, std::back_inserter(c3));

print(c3);
}
return 0;
}

Happy coding!

Function reading from a file into vector C++

I have written a function that reads an unknown number of data (when in a column) from a file to a vector.

One of the most elegant (and, I suppose, idiomatic) ways to read unknown amount of data from a "column" (or otherwise regularly-formatted) file is to use istream iterators:

void ReadFromFile(std::vector<double> &x, const std::string &file_name)
{
std::ifstream read_file(file_name);
assert(read_file.is_open());

std::copy(std::istream_iterator<double>(read_file), std::istream_iterator<double>(),
std::back_inserter(x));

read_file.close();
}

Usage:

int main()
{
// Note the default constructor - we are constructing an initially empty vector.
std::vector<double> rx;
ReadFromFile(rx, "Loadrx.txt");
}

If you want to write a "safe" version with a limited number of elements to read, use copy_if:

void ReadFromFile(std::vector<double> &x, const std::string &file_name, unsigned int max_read)
{
std::ifstream read_file(file_name);
assert(read_file.is_open());

unsigned int cur = 0;
std::copy_if(std::istream_iterator<double>(read_file), std::istream_iterator<double>(),
std::back_inserter(x), [&](const double&) {
return (cur++ < max_read);
});

read_file.close();
}

Usage is obvious:

ReadFromFile(rx, Loadrx, max_numbers);

Best way to read a files contents and separate different data types into separate vectors in C++

You are asking here how you should approach the given problem.

In normal software development we do several steps. First, we analyze the requirements, then think of a design and after that, we start coding. And finally, we verify and qualify the program. In reality there are more processes. But please take one important recommendation:

Before writing code. We should first clarify the “What” and then the “how”.

Last, but not least, when doing the coding, we should follow standard patterns to avoid the most common problems.

So, now let us look at your problem. You want to read a text file. The text file contains lines with comma separated values. The lines, with the comma separated values shall be split.

Then, there are always 2 lines that belong together. The first line contains index as a integer number and the question as a string, the second line consists of also an integer index and then an integer number denoting the answer.

All the data shall be read and stored for further processing.

At this point in time, we have done the requirement analysis in general.

Next is the “How”, the design, the “how we want to do things”

You were mentioning that you want to use 2 different vectors to store the questions and the answers. That approach is basically not that good.

Because the general rule is that you should store values that belong somehow together, even having different types, like int and string, in a “struct” or “class”. The same is valid for data in the first and then in the next line.

On the other hand, many data having the same type, should store in a container, like a std::array or std::vector (or others, depending of the use case).

And in your case, you would have a combination of both. So, first the data with different types in a struct and then a std::vector of these structs.

Example for the above (one of many possible solutions):

#include <iostream>
#include <vector>

struct Question {
int index{};
std::string text{};
};
struct Answer {
int index{};
int data{};
};

struct QuestionAndAnswer {
Question question{};
Answer answer{};
};

std::vector<QuestionAndAnswer> questionAndAnswer{};

OK, understood next.

We want to open a file and read it line by line. Opening a file for reading, can be done by defining a std::ifstream and then handing a filename to its constructor. This will open the file for you. And, at the end, when the variable of type std::ifstream falls out of scope, then destructor of the std::ifstream will automatically close the file for you.

You should always check the CPP Reference for any kind of questions to C++ functionalities.

As a general rule, you should always check the result of any IO-operation. This can be done with if (ifstreamVaraible). If you look in the definition of the IO-Stream functions than you can see that many of them return again a reference to the IO-Stream, with which that have been called. Example:

// Open the file
std::ifstream sourceFileStream(“test.txt”);

// Check, if it could be opened successfully
if (sourceFileStream) {

// Read the line and get the result
std::string line{};
if (std::getline(sourceFileStream, line)) {
. . .
}

How does this work? If you look in the documentation of the stream functions, then you will see that their bool and not operator ! are overwritten and return the status of a stream. For the above example if (sourceFileStream) { the compiler sees a stream variable in an if-statement, were it expects a boolean expression. It will then take the bool function of the stream and evaluates it.

Same is valid for if (std::getline(sourceFileStream, line)). This will first do the getline - operation, which will read the line. And then getline returns a reference to the stream. Then the if- statement contains quasi again if (sourceFileStream) and the bool operator will be called.

With this mechanism, you can (and should) check the result of all IO-operations.

If we want to read many lines in a loop then the rule is, to put the std::getline(sourceFileStream, line) statement into the while statements condition part. Otherwise you will always read a line to much.

You will see from not so experienced developers often something like ‘while (!sourceFileStream.eof())’ or, similar, while (sourceFileStream). This is considered to be wrong. There are many many statements her on SO, explaining that in more detail.

Next, if you want to learn C++ and use better approaches, then you should make use of object-oriented programming. The first step is, to put data and methods operating on this data in one class or struct. For your case, it would mean that the input functions should be part of the structs.

In C++ input is done via the extractor operator >>. And therefore we should add an extractor operator to your structs.

The syntax for that is (with the example of the answer struct=:

struct Answer {
int index{};
int data{};

friend std::istream& operator >> (std::istream& is, Answer& a) {
// Read an index, a comma, and the answer
char comma{};
return is >> a.index >> comma >> a.data;
}
};

This is a function for the class(or struct) “Answer”, that takes a stream and an answer as input and will return again a reference to the stream. Now, we could write:

Answer answer{};
if (!(std::cin >> answer))
std::cerr << “Problem while reading answer\n”;

The if- statement will execute the embedded extraction operation. The compiler will see a stream, the extractor operator >> and a variable of type Answer. So, it will call the function defined in the above struct. The operation will return a reference to the stream and the ! operator of the stream, will indicate, if the stream ha and issue.

A similar mechanism can be implemented for output, so we can overwrite the inserter operator >> as well.


With all that, we can split the above big problem into very small units, which can be implemented in an easy and understandable way.



Related Topics



Leave a reply



Submit