Why Does getline() Doesn't Read anything from a file? - c++

I have made a code which accepts a txt file as input, and parse, and put them in 2d array myarray[][2].
Input file structure looks like this:
aaa/bbb
bbb/ccc
ccc/ddd
And it should be parsed like this:
myarray[0][0] = "aaa"
myarray[0][1] = "bbb"
myarray[1][0] = "bbb"
myarray[1][1] = "ccc"
The code which I made to do this:
void Parse_File(string file){
ifstream inFile;
inFile.open(file);
if (inFile.is_open()){
inFile.clear();
int lines = count(istreambuf_iterator<char>(inFile), istreambuf_iterator<char>(), '\n');
string myarray[lines][2];
int mycount = 0;
do{
getline(inFile, input);
myarray[mycount][0] = input.substr(0, input.find("/"));
myarray[mycount][1] = input.substr(input.find("/") +1, input.length());
mycount++;
}while (input != "");
}else{
Fatal_Err("File Doesn't Exist");
}
inFile.close();
}
But myarray doesn't have anything in it after this function. The do-while statement doesn't loop. I can't figure out why. Any help is appreciated. Thanks.

Your file had a few issues, but the major one was: You forgot to bring your file reading pointer back to the beginning of the text document. The count function took the said pointer to the end, so you needed to bring it back.
So you need to use the seekg() function to drag the pointer wherever you wish to.
See if the code below works for you
void Parse_File(string file)
{
ifstream inFile;
inFile.open(file);
if (inFile.is_open())
{
inFile.clear();
int lines = count(istreambuf_iterator<char>(inFile), istreambuf_iterator<char>(), '\n');
//Pitfall : By counting the lines, you have reached the end of the file.
inFile.seekg(0);// Pitfall solved: I have now taken the pointer back to the beginning of the file.
....
....//Rest of your code
}
}
Also, you need to learn debugging so that you understand your code more easily. I would recommend visual studio code for debugging c++.

Move "getline(inFile, input);" to the end of your loop and call it again right before you enter. input is probably "" before you enter the loop, so the loop is never called and input is never updated.

Related

Issue reading multiple lines from .txt file in C++

I'm trying to create a student database system for a school project. I'm trying to create a function that will search a .txt file for the student id and return all of the other variables on the string. This is working great if I search for the id of the student on the first line of the txt file but isn't capturing anything if I search for a student on another line. Am I missing something obvious?
The student data is 16 strings delimited by commas on each line. The student ID is the first string.
Thanks for any assistance!
StudentType findStudent(int studentToFind)
{
ifstream inFile;
inFile.open("students.txt");
string currentLine;
string dataRead[16];
istringstream is;
int currentStudent;
if (inFile)
{
while (getline(inFile, currentLine))
{
is.str(currentLine);
for (int i = 0; i < 16; i++)
{
getline(is, dataRead[i], ',');
}
currentStudent = stoi(dataRead[0]);
if (currentStudent == studentToFind)
{
/*
Do stuff here
*/
inFile.close();
return foundStudent;
}
cin.ignore(); // Not sure if this is needed but I was trying to
// clear the \n char if that was causing the issue
}
}
}
First : you aren't using cin, so get rid of cin.ignore().
Second : you should make sure you ALWAYS close infile at the end... so I would suggest not returning early or closing early, but using a break statement to exit your loop and then have a single return of whether you found it or not.
Third: Now that you removed all the 'gorp' we can finally hone in on the problem ... effectively the question is do we read all the lines?
Well let's check that, try printing out currentLine each time at the beginning of the while loop, if you know currentLine is updated properly, is is getting updated each time? yes...
ok then look at your next loop let's print out currentStudent each time... does currentStudent print the right value for each line? i.e. is the getline write into dataRead[i] actually writing what you think it should be to the right space?
Did you find the problem yet?
This is the kind of problem you need to learn how to solve yourself using print statements and a debugger. That what its for. If you are in visual studio run in debug mode and step through it... if not, use gdb. learn it and get used to it, you'll be using it a lot!
good luck

How to read content of the file and save it to string type variable? Why there is empty space?

This is how I get the name of the file from the command line and open a file and save the content of the file line by line to a string. All the procedures works fine except three empty spaces at the beginning of the file. Is anyone can say why these empty spaces occurred and how can I ignore them?
string filename = "input.txt";
char *a=new char[filename.size()+1];
a[filename.size()]=0;
memcpy(a,filename.c_str(),filename.size());
ifstream fin(a);
if(!fin.good()){
cout<<" = File does not exist ->> No File for reading\n";
exit(1);
}
string s;
while(!fin.eof()){
string tmp;
getline(fin,tmp);
s.append(tmp);
if(s[s.size()-1] == '.')
{
//Do nothing
}
else
{
s.append(" ");
}
cout<<s<<endl;
The most probable cause is that your file is encoded in something else than ASCII. It contains a bunch of unprintable bytes and the string you on the screen is the result of your terminal interpreting those bytes. To confirm this, print the size of s after the reading is done. It should be larger than the number of characters you see on the screen.
Other issues:
string filename = "input.txt";
char *a=new char[filename.size()+1];
a[filename.size()]=0;
memcpy(a,filename.c_str(),filename.size());
ifstream fin(a);
is quite an overzealous way to go about it. Just write ifstream fin(a.c_str());, or simply ifstream fin(a); in C++11.
Next,
while(!fin.eof()){
is almost surely a bug. eof() does not tell if you the next read will succeed, only whether the last one reached eof or not. Using it this way will tipically result in last line seemingly being read twice.
Always, always, check for success of a read operation before you use the result. That's idiomatically done by putting getline in the loop condition: while (getline(fin, tmp))

Missing line of data using Getline with Ifstream

Ok so this is killing me at the moment cause its such a simple part of my program that just doesn't want to work. I'm reading data from a textfile to use in a GA.
The first getline() works perfectly, but the second one doesn't want to write any data into my string. When i cout the string it doesn't show anything.
Here is the code:
ifstream inFile;
inFile.open(fname.c_str());
char pop[20], mut[20];
inFile.getline(pop,20);
cout << pop;
inFile.getline(mut,20);
cout << mut; //this outputs nothing
Thanks for any help in advance.
A sample form my file:
there is no line between them mutation is the line straight after population
Population size: 30
Mutation: 20
Your file's first line is 20 characters long (19+new line) but pop[20] can only contain 19 (because the last one is reserved for the null terminator '\0').
When istream::getline stops because it has extracted 20-1 characters, it doesn't discard the new line delimiter (because it was never read). So the next getline just reads the end of the first line, discarding the new line.
That's why you get nothing in the second string.
Your problem is that the length of your input line exceeds the length of the buffer which must hold it.
The solution is to not use character arrays. This is C++, use std::string!
std::ifstream inFile;
inFile.open(fname.c_str());
std::string pop;
std::getline(inFile, pop);
cout << pop << "\n";
std::string mut;
std::getline(inFile, mut);
cout << mut << "\n";
I think you need to find out what the problem is. Add error checking code to your getline calls, refactor the (simple) code into a (simple) function, with a (simple) unittest. Possibly, your second line is longer than the assumed 20 characters (null-term included!).
For an idea of what I mean, take a look at this snippet.
try something like
while (getline(in,line,'\n')){
//do something with line
}
or try something like
string text;
string temp;
ifstream file;
file.open ("test_text.txt");
while (!file.eof())
{
getline (file, temp);
text.append (temp); // Added this line
}

Reading BSDF data format

I have been required to write a function that reads the BSDF data format defined by Zemax
An example of such file can be found at the following page: BSDF file example
I would like to use, if possible, only standard ifstream functions.
I have already prepared all the necessary datamembers inside a dedicated class.
I am now trying to write the function that reads the data from the file.
Problems:
how do I exclude comment lines? as documented, they start with an hash # I was going for something like
void ReadBSDFFile(myclass &object)
{
ifstream infile;
infile.open(object.BRDFfilename);
char c;
infile.get(c);
while (c == "#") // Problem, apparently I cannot compare in this way. How should I do it?
{
getline(infile, line);
infile.get(c);
}
// at this point I would like to go back one character (because I do not want to lose the non-hash character that ended up in *c*)
infile.seekg(-1, ios_base::cur);
// Do all the rest
infile.close();
}
in a similar way, I would like to verify that I am at the correct line later on (e.g. the "AngleOfIncidence" line). Could I do it in this way?
string AngleInc;
infile >> AngleInc;
if (AngleInc != "AngleOfIncidence")
{
//error
}
Thanks to anyone who will comment/help. Constructive criticism is welcomed.
Federico
EDIT:
Thanks to Joachim Pileborg below, I managed to proceed up to the data blocks part of the file.
Now I have the following problem. When reaching the datablocks, I wrote the following piece of code, but at the second iteration (i = 1) i receive the error message for the TIS line.
Could someone help me understand why this does not work?
Thanks
Note: blocks is the number on the AngleOfIncidence line, rows the one on the ScatterAzimuth line and columns the one on the ScatterRadial. I tested and verified that this part of the function works as desired.
// now reading the data blocks.
for (int i=0; i<blocks; i++)
{
// TIS line
getline(infile, line);
if (line.find("TIS") == string::npos)
{
// if not, error message
}
// Data block
for (int j=0; j<rows; j++)
{
for (int k=0; k<columns; k++)
{
infile >> object.BRDFData[i][j][k];
}
}
}
EDIT 2:
solved adding infile.seekg(+2, ios_base::cur); as a last line of the i loop.
The reading loop could be simplified like this:
std::string line;
while (getline(infile, line))
{
if (line[0] != '#')
{
// Not a comment, do something with the line
if (line.find("AngleOfIncidence") != std::string::npos)
{
// On the AngleOfIncidence line, do special things here
}
}
}
It's might not be optimal, just something written at the top of my head, but should work.
From the description of the format you provided:
Any line that starts with the # symbol is ignored as a comment line.
So what you need to do is the following
Read the file line by line
If the line starts with # ignore it
Otherwise process the line.
The while you have used is wrong. Use the getLine function instead and compare its first character with the #.

reading data from files, file name as input

I am writing a program which reads data from different files, which are given as input strings, and stores them into a vector of vectors. The problem I am not able to debug the loop which reads different files. I have closed the ifstream object, cleared the string using empty function... but still it just terminates when i give second file name as input.
I am copying the code for your perusal. It is a function called by another another function. Transposectr transposes a matrix.
code:
vector<vector<float> > store1,store2;
ifstream bb;
string my_string;
float carrier;
vector<float> buffer;
cout<<"enter the file name"<<endl;
getline(cin,my_string);
while (my_string!="end")
{
bb.open(my_string.c_str());
while (!bb.eof())
{
bb >> carrier;
if (bb.peek() == '\n' || bb.eof() )
{
buffer.push_back(carrier);
store1.push_back(buffer);
buffer.clear();
}
else
{
buffer.push_back(carrier);
}
}
bb.close();
buffer.clear();
transposectr1(store1);
storex.push_back(store1[1]);
storey.push_back(store1[0]);
store1.clear();
my_string.empty();
cout<<"done reading the file"<<endl;
cout<<"enter the file name"<<endl;
getline(cin,my_string);
}
I'm really not clear what you are trying to do. But I have one golden ruile when it comes to using istreams:
Never use the eof() function!
It almost certainly does not do what you think it does. Instead you should test if a read operation succeeded.
int x;
while( in >> x ) {
// I read something successfully
}
You might also want to avoid peek() too. Try re-writing your code with this advice in mind.
Add
bb.clear();
after the bb.close() you may get the right thing. bb.close() doesn't reset the cursor I think.
Neil Butterworth is right
Never use the eof() function!
This link explains why.