I want to get some data from file and put it to variables. But before, I don't know the length of this file. File looks like:
1 12 4
2 14 5
3 26 6
. .. .
That's why I want to get a number of lines to know, how much variables I need to create in loop. In this code I created 3 variables (a,b,c) to try. The problem is that after the end of program a,b,c are just random numbers instead of 1, 12 and 4.
I noticed that if I put this:
file >> a >> b >> c;
before while loop it works, but I need number of lines earlier.
So how to count lines not using getline() ?
int a, b, c;
fstream file;
file.open("abc.txt",ios::in);
if (file.good() == true)
{
int lines_amount=0;
string test;
while (getline(file,test))
{
lines_amount++;
}
file >> a >> b >> c;
file.close();
}
When you use
while (getline(file,test))
{
lines_amount++;
}
the while loop stops only after everything from the file has been read. The line
file >> a >> b >> c;
does not read anything into a, b, or c. The values of those variables are some random values that you get since they have not been initialized before.
Initialize them to something like:
int a = 10, b = 20, c = 30;
and you will notice that:
If you use a pre-C++11 compiler, the values of those variable remain unchanged.
If you use a C++11 or later compiler, the values of those variables will be set to 0.
To be able to read the numbers from the start of the file, rewind it to the top. You can use std::ifstream::seekg for that. You have to clear its eofbit first though.
file.clear();
file.seekg(std::ifstream::beg);
What about rewinding the file indicator?
file.seekg(std::ifstream::beg);
In the previous while loop, the whole file has already been read, so there's nothing left for the next read, and a, b and c remain untouched. After this code, the file indicator is reset to the beginning of the file, so you're able to read from start again.
You may need to add file.clear() before calling seekg() to clear any flags that are already set, to prevent further operations from failing. Most of them don't do anything if a bad flag is set. In your case, when attempting to read more, the operator >> () function finds a bad flag (std::ios_base::iostate::eofbit) and stops. Further Reference
That's why i want to get a number of lines to know, how much variables i need to create in loop.
You don't need to know the number of lines beforehand. Use a std::vector to store the values, and let it grow dynamically as you add values into it. For example:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
struct values {
int a, b, c;
};
std::vector<values> data;
std::ifstream file("abc.txt");
if (file.is_open()) {
std::string line;
while (std::getline(file, line)) {
std::istringstream iss(line);
values v;
if (iss >> v.a >> v.b >> v.c) {
data.push_back(v);
}
}
file.close();
// use data as needed...
}
Alternatively:
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <algorithm>
struct values {
int a, b, c;
};
std::istream& operator>>(std::istream &in, values &v) {
std::string line;
if (std::getline(in, line)) {
std::istringstream iss(line);
if (!(iss >> v.a >> v.b >> v.c)) {
in.setstate(std::ios_base::failbit);
}
}
return in;
}
std::vector<values> data;
ifstream file("abc.txt");
if (file.is_open()) {
std::copy(
std::istream_iterator<values>(file),
std::istream_iterator<values>(),
std::back_inserter(data));
file.close();
// use data as needed...
}
Related
I have written a code here which reads a input file line by line and creates a vector of vectors which I then use as a matrix, later on, in my homework. This is the code:
vector<vector<int>> inputMatrix;
string line;
while(!file.eof())
{
getline(file, line);
stringstream ss(line);
int num;
vector<int> temp;
while(ss >> num)
{
temp.push_back(num);
}
inputMatrix.push_back(temp);
}
However, some input files may contain non-integer values. I would like to integrate a input check feature for the matrix creation so that when there is a non-integer value in the input file, my program would quit.
How can I achieve this? Would it be possiple to write somewhere in this while loop or somewhere else in the code?
thank you very much in advance.
From cppreference.com:
If extraction fails, zero is written to value and failbit is set. If
extraction results in the value too large or too small to fit in
value, std::numeric_limits::max() or std::numeric_limits::min()
is written and failbit flag is set.
So you could simply add an if clause after your while loop:
while (ss >> num)
{
temp.push_back(num);
}
if (ss.fail()) // explicitly check for failbit
{
expected_integer_error();
}
I would like to integrate a input check feature for the matrix creation so that when there is a non-integer value in the input file, my program would quit.
The stringstream already does this check for you. You can simply test its state after the while loop. If it failed to parse a non integer value, the failbit will be set to true.
Here's a working demo (with some small improvements):
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
int main() {
vector<vector<int>> inputMatrix;
string line;
while(getline(cin, line))
{
istringstream iss(line);
int num;
vector<int> temp;
while(iss >> num)
{
temp.push_back(num);
}
if(!iss) {
cout << "Bad input detected!" << endl;
return 1;
}
inputMatrix.push_back(temp);
}
return 0;
}
Input
12 13 46 3
42 2.6 5
Output
Bad input detected!
psedo code:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string line;
double beta[250];
char Batob[250], eq[250];
ifstream myfile("iter1/HMMemit0.txt");
if (myfile.is_open())
{
int i = 0;
while (getline(myfile, line))
{
istringstream iss(line);
if (!(iss >> Batob[i] >> eq[i] >> beta[i])){ //it store only B in Batob[i], but i want to save B00 in Batob[i], = in eq[i], and 0.524671 in beta[250]
break;
}
i++;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
my data stored in HMMemint0 like this
B00 = 0.524671
B01 = 0.001000
B02 = 0.001000
B10 = 0.001097
B11 = 0.001000
B12 = 0.001000
i want to read a line and save each term in each variable like B00 saved in name[i], and 0.001000 in beta[i].
and then, write it in this 0.524671(B00's value) 0.001097(B10's value) order like this
0.524671 0.001097
0.001000 0.001000
0.001000 0.001000
How can i do it? please help me.
You are having a char array for "BXX"s, whereas you want strings. Basically, you want a string array, or even vector. The problem is that only 'B' will be read from "BXX" into your first parameter.
This code works for me:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
int main() {
string line;
double beta[250];
string Batob[250];
char eq[250];
ifstream myfile("iter1/HMMemit0.txt");
if (myfile.is_open())
{
int i = 0;
while (getline(myfile, line))
{
istringstream iss(line);
iss >> Batob[i] >> eq[i] >> beta[i];
i++;
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
Disclaimer: I was just fixing your code with the least impact, but of course if you start using proper C++ containers like vector, the i variable could be easily eliminated as the elements and the index would be maintained automatically.
Also, since you are using the equal sign ('=') all the time for the char array, it is a bit needless waste of memory, which could be severe in case of a big file.
I would say, using an associate container in the future would be even more productive for your BXX keys and their corresponding values on the right side.
Batob is an array of characters, so Batob[i] is a single character. That's why your program reads only one character. If you want to read 250 strings of characters you need to make room for them. The simplest (not necessarily the best, however) method is to declare an array like char Batob[250][100] – this would be an array of 250 arrays, 100 characters each. Then Batob[i] is a 100-chars array and you can input a string with iss >> Batob[i].
Hey all so I have to get values from a text file, but the values don't stand alone they are all written as this:
Population size: 30
Is there any way in c++ that I can read from after the ':'?
I've tried using the >> operator like:
string pop;
inFile >> pop;
but off course the whitespace terminates the statement before it gets to the number and for some reason using
inFile.getline(pop, 20);
gives me loads of errors because it does not want to write directly to string for some reason..
I don't really want to use a char array because then it won't be as easy to test for the number and extract that alone from the string.
So is there anyway I can use the getline function with a string?
And is it possible to read from after the ':' character?
#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;
int main()
{
string fname;
cin >> fname;
ifstream inFile;
inFile.open(fname.c_str());
string pop1;
getline(inFile,pop1);
cout << pop1;
return 0;
}
ok so here is my code with the new getline, but it still outputs nothing. it does correctly open the text file and it works with a char array
You are probably best to read the whole line then manipulate the string :-
std::string line;
std::getline(inFile, line);
line = line.substr(19); // Get character 20 onwards...
You are probably better too looking for the colon :-
size_t pos = line.find(":");
if (pos != string::npos)
{
line = line.substr(pos + 1);
}
Or something similar
Once you've done that you might want to feed it back into a stringstream so you can read ints and stuff?
int population;
std::istringstream ss(line);
ss >> population;
Obviously this all depends on what you want to do with the data
Assuming your data is in the form
<Key>:<Value>
One per line. Then I would do this:
std::string line;
while(std::getline(inFile, line))
{
std::stringstream linestream(line);
std::string key;
int value;
if (std::getline(linestream, key, ':') >> value)
{
// Got a key/value pair
}
}
i would like to request some help on theory part, so grind those gears, here it comes
I want to load a file into my program, which looks something like this:
0,10,10#0,100,40...
Okay what i now want to do is to take out every comma separated number and send it through my function
void func( int, float, float );
The hashtag means it's a new block, so it would be sent like func(0,10,10) and after that it would send func(0,100,40) and so on.
I was thinking to check every char until i meet ',' and after that put it in a vector, and continue that until the '#' is met. Then it would fire away my function (like func(v[0],v[1],v[2]) and then just do the same thing over and over until EOF!
Is this a good way to go? Have any better ideas? Those numbers can also get very large later on, so i don't know how much memory i need (therefor the vector). Or should i just go with 3 temp ints and floats and then fire the function and start over!
Going char by char and using a state machine like you suggested is the fastest way.
However the easiest way is first to split by the # and then for each result string split by ,.
You can use boost library to do the string split.
#include <fstream>
#include <ostream>
#include <istream>
#include <stdexcept>
void func( std::vector<float> &numbers )
{}
int main() {
std::ifstream myfile("myfile.txt");
float number;
char seperator;
std::vector<float> numbers;
while( myfile >> number) { //read number
numbers.push_back(number); //and remember it
if (!(myfile >> seperator) || seperator == "#") { //if # or EOF or error
func(numbers); //run function
numbers.clear(); //and start over
}
} //only gets here at EOF or malformed file
return 0;
}
Very simple, fast, and easy.
If you're certain the file starts with the first int of a group of three
ifstream fin("foo.csv");
string str;
stringstream s_str;
while(!fin.eof())
{
int a;
float b,c;
getline(fin,str,',');
s_str.str(str);
s_str >> a;
getline(fin,str,',');
s_str.str(str);
s_str >> b;
getline(fin,str,'#');
s_str.str(str);
s_str >> c;
}
should work. (I haven't compiled it so there might be typos etc)
I have a text file that contains the following data.
The first line is this:
5 4 3 2 1
The second line is this:
1 2 3 4 5
I am trying to read data from one line at a time because my first linked-list object is going to use the data from the first line and my second linked-list object is going to use data from the second line. The best I have been able to come up with is the following function:
void polynomial::allocate_poly(std::ifstream& in, const char* file, const char* number)
{
in.open(file);
std::string str;
char b;
int m = 0;
for(int i = 0; !in.eof(); ++i)
{
in >> b;
m = b - '0';
a.insert(m);
}
There is a few problems with this approach. I have tried different binary operators in my for loop such as b == '\n' and none of them seem to trigger when b is a newline character.
Also allocating the numbers from the file this way it looks like
5 5 4 3 2 1 1 2 3 4 5 , so it seems to be copying an extra 5 somewhere, I am not sure if this is the eof bit or not.
I have also attempted to use the getline function but for some reason it seems to only copy the first integer and then dumps the rest of the file. I know certainly I am not using it correctly but all the examples I can find are for typing the file name such as cin.getline and I want to be able to pass my file name as a command line argument when running the program instead.
My question is how can I allocate the numbers on the first row up to the newline char and then pass the ifstream in variable to another object to allocate the second line? Thanks for your help.
You don't say what a is, but never mind: If you want line based parsing, you need to have getline in the outer loop. Also, never use eof, as it doesn't do what you want. Rather use the implicit conversion to bool to check if an operation succeeded.
Here's the typical gig:
#include <sstream>
#include <fstream>
#include <string>
std::string line;
std::ifstream infile("myfile.txt");
while (std::getline(infile, line)) // this does the checking!
{
std::istringstream iss(line);
char c;
while (iss >> c)
{
int value = c - '0';
// process value
}
}
However, this conversion from char to int is cumbersome and fragile. Why not read an integer directly?
int value;
while (iss >> value) { /* ... */ }
Edit: Based on your comment, here's the code to read exactly two lines:
std::string line;
int val;
if (std::getline(infile, line))
{
std::istringstream iss(line);
while (iss >> value) { /* process first line */ }
}
if (std::getline(infile, line))
{
std::istringstream iss(line);
while (iss >> value) { /* process second line */ }
}