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:
- Read a complete line as a
std::string
- Split this string into substrings using the comma as a separator
- 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
- Handcrafted, many variants, using pointers or iterators, maybe hard to develop and error prone.
- Using old style
std::strtok
function. Maybe unsafe. Maybe should not be used any longer std::getline
. Most used implementation. But actually a "misuse" and not so flexible- 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
C++ Class Wrapper Around Fundamental Types
Why Does Constexpr Static Member (Of Type Class) Require a Definition
Does Std::Mutex Create a Fence
How to Implement No-Op MACro (Or Template) in C++
Convert Char Array to Single Int
Why Sizeof Int Is Wrong, While Sizeof(Int) Is Right
How to Pass Multiple Ints into a Vector at Once
Why Doesn't This Reinterpret_Cast Compile
Are There Binary Memory Streams in C++
Visual Studio 2010 & 2008 Can't Handle Source Files with Identical Names in Different Folders
Qobject: Cannot Create Children for a Parent That Is in a Different Thread
C++11 Virtual Destructors and Auto Generation of Move Special Functions