Reading BSDF data format - c++

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 #.

Related

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

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.

C++: Using getline to input from a text file either skips the first line or messes up the rest

I'm trying to read in from a specially formatted text file to search for specific names, numbers, etc. In this case I want to read the first number, then get the name, then move on to the next line. My problem seems to be with while loop condition for reading through the file line by line. Here is a sample of the txt file format:
5-Jon-4-Vegetable Pot Pie-398-22-31-Tue May 07 15:30:22
8-Robb-9-Pesto Pasta Salad-143-27-22-Tue May 07 15:30:28
1-Ned-4-Vegetable Pot Pie-398-22-31-Tue May 07 15:30:33
I'll show you two solutions I've tried, one that skips the first line in the file and one that doesn't take in the very last line. I've tried the typical while(!iFile.eof()) as a last ditch effort but got nothing.
transactionLog.clear();
transactionLog.seekg(0, std::ios::beg);
std::string currentName, line, tempString1, tempString2;
int restNum, mealNum;
bool nameFound = false;
int mealCount[NUMMEALS];
std::ifstream in("patronlog.txt");
while(getline(in, line))
{
getline(in, tempString1, '-');
getline(in, currentName, '-');
if(currentName == targetName)
{
if(getline(in, tempString2, '-'))
{
mealNum = std::stoi(tempString2);
mealCount[mealNum - 1] += 1;
nameFound = true;
}
}
I believe I understand what's going in this one. The "getline(in, line)" is taking in the first line entirely, and since I'm not using it, it's essentially being skipped. At the very least, it's taking in the first number, followed by the name, and then doing the operations correctly. The following is the modification to the code that I thought would fix this.
while(getline(in, tempString1, '-'))
{
getline(in, currentName, '-');
// same code past here
}
I figured changing the while loop condition to the actual getline of the first item in the text file would work, but now when I look at it through the debugger, on the second loop it sets tempString1 to "Vegetable Pot Pie" rather than the next name on the next line. Ironically though this one does fine on line #1, but not for the rest of the list. Overall I feel like this has gotten me farther from my intended behavior than before.
You need to parse the contents of lines after they are read. You can use a std::istringstream to help you with that.
while(getline(in, line))
{
// At this point, the varible line contains the entire line.
// Use a std::istringstream to parse its contents.
std::istringstream istr(line);
getline(istr, tempString1, '-'); // Use istr, not in.
getline(istr, currentName, '-'); // ditto
...
}

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

lineBuffer in C++

I was just browsing some coding stuff and noticed this code:
int main(int argc,char** argv)
{
ifstream file;
string lineBuffer;
file.open(argv[1]) ;
while (!file.eof())
{
getline(file, lineBuffer);
if (lineBuffer.length() == 0)
continue; //ignore all empty lines
else
{
//do your code here
}
}
return 0;
}
I have searched for the concept of a lineBuffer all over the net but found no relevant answer.
Can anyone help me to understand how lineBuffer is used to read a file line by line?
string lineBuffer;
This is a variable called lineBuffer. It's not a concept to be understood and it doesn't read files, it's just a string with a name, it could just as easily have been called:
string fred;
but because it is used as a buffer to hold each line of text, it is more sensible and helpful to call it lineBuffer.
Wherever you found that code, stop reading it, the code is broken and written by someone who doesn't know C++ very well. This part is broken:
while (!file.eof())
{
getline(file, lineBuffer);
It should be done like this instead:
while (getline(file, lineBuffer))
{
The lineBuffer is a string where you are asking C++ to put the line it reads. Once the line is in that string, they check whether there was any content in that line, and if not, skip processing it.

Using multiple instances of getline in C++

I've been working on a class assignment for C++ and we're required to acquire input from a text file and assign those values to an array....one is a string, the second an int, and the third a double.
We've only been introduced to arrays and I don't know anything yet about pointers or linked lists, or any of the higher end stuff, so I feel like I'm somewhat limited in my options. I've worked all day trying to figure out a way to acquire input from the text file and assign it to the appropriate array. I've tried to use getline to read the input file and set a delimiter to separate each piece of data but I get an error when I try to use it more than once. From what I've read, this has to do with how I'm overloading the function but I'm at a loss at resolving it. Every explanation I've read about it goes beyond my current level of familiarity. Right now, I'm focused on this fragment of code:
for (int i = 0; i < EMP_NUM; i++) // Get input from text file for names.
getline(inFile, nameAr[i], '*');
for (int i = 0; i < EMP_NUM; i++) // Input for hours.
getline(inFile, hoursAr[i], '*');
for (int i=0; i < EMP_NUM; i++) // Input for hourly rate.
getline(inFile, hrateAr[i], '*');
I'm trying to use getline three times and write the data to three separate arrays, then make a series of calculations with them later and output them to another text file. The first instance of getline doesn't produce any compiler errors but the latter two do. I'm not quite sure of another solution to get the data into my arrays, so I'm at a loss. Any help would be great!
If I understand correctly you merely have three values in a file: a string, an int and a double. I assume they are delimited by whitespace.
If that is so then you don't need std::getline(). Rather, use the extraction operator:
std::ifstream file("input.txt");
std::string s;
if( ! (file >> s) ) { // a single word extracted from the file
// failure
}
int n;
// ...
1) Instead of three different iteration, use only one
2) Pass string object in getline instead of pointers
string buf;
for (int i = 0; i < EMP_NUM; i++) // Get input from text file for names.
{
getline(inFile, buf, '*');
nameAr[i] = buf;
getline(inFile, buf, '*'); //assuming delimiter is again *
hoursAr[i] = atoi(buf.c_str() ); //C way to doing it...however in c++ u have to use stringstreams....
getline(inFile, buf);
hrateAr[i] = atof(buf.c_str() );;
}
What do the compiler errors say? Are you sure that the error is caused by getline? Maybe it's not because the getline calls but because of multiple declarations of i.