# Read large amount of numbers from file

• 05-09-2007
h3ro
Read large amount of numbers from file
Hallo,

I am working on a function for reading large amount of data from a file. Each line contains the information needed to build a triangle. What is the best way to do this?

Right now Im tying to read each line, convert it into a float and than create a triangle before I read the next line. Is there a smarter way? Would be great to get some input on this.

Code:

std::string currentLine;            // Variable that holds the current line
// we are using.
int nrLines = 0;                    // Variable for checking how many lines
// there are in the file

// Open file
std::ifstream myFile (FileName);

/*
// The content of the file
random line  11 ra
V: 2.020,0.121,12.1212 4.657,11.31,9.11 4.7,11.00,5.411
V: 2.020,0.121,12.1212 4.657,11.31,9.11 4.7,11.00,5.411
V: 2.020,0.121,12.1212 4.657,11.31,9.11 4.7,11.00,5.411
V: 2.020,0.121,12.1212 4.657,11.31,9.11 4.7,11.00,5.411
*/

// An array of strings, for reading the 3 vertexes we will later
// use. Note that there is 3 vertexes, each made up of 3
// cordinates
std::string vertex[3][3];

if (myFile.is_open())
{
// While the file is open, we read the info and construct triangles
while (! myFile.eof())
{
getline(myFile, currentLine);

// Check if this line holds vertex information. If the line starts
// with V, we will use it.
if (currentLine[0] == 'V')
{
// Break the line into different components, so that we can
// create 3 different vertexes for each cordinate in the file
// V: 0.0,0.0,0.0 1.0,1.0,1.0 2.0,2.0,2.0

// Variable for keeping track of which character in currentLine
// we are reading, it starts at 2, as the 3 first characters
// are not part of the number we are tring to read
int x = 3;

// Make a loop for creating 3 vertexes
for (int i = 0; i < 3; i++)
{
// Loop for looping throught the three cordinates of each
// vertex
for (int j = 0; j < 3; j++)
{
// Make sure the vertex string we are writing to now is
// empty
vertex[i][j].clear();

// Make sure the current character is part of the number
while (currentLine[x] != ',' && currentLine[x] != ' ')
{
// If the current character is part of a number,
// append it to the vertex string
vertex[i][j].push_back(currentLine[x]);
x++;
}
x++;
}
}
// Convert the string into floats
}
// Increment the line counter
nrLines++;
}
// Finished with reading the file, close it
myFile.close();
}

I also have a problem with the printing. I get a lot of random characters after i have printed the numbers.
Code:

// Print the thing
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
std::cout << vertex[i][j] << " ";
}
std::cout << " - ";
}

std::cout << std::endl;

EDIT:
Right now Im trying to load my own file format, which kind of suck. Does anyone know where to find good information on how to load .obj files? I have looked, but could not find anything good (simple)

Thanks again
• 05-09-2007
Oldman47
Obj (Model files) have 3 vertice cords per line, not the 9 you're doing. I've never seen a text-based model format like the one you're developing before.

-0.252000 0.169971 0.008000 //this is standard (as you probably already know).

I'm not certain, but I think you could actually read the floats directly from a file such as;

Code:

float getcord;

ifstream in("model.obj", ios::in | ios::binary)
in>>getcord;

I'd dump the comma separator, btw. Just use a space. Some use the comma as a decimal point, so that can get confusing -
• 05-10-2007
h3ro
Quote:

Obj (Model files) have 3 vertice cords per line, not the 9 you're doing. I've never seen a text-based model format like the one you're developing before.
This is what I get when I try to export from Maya. What are all the stuff at the end?
Also, when I open the file, everything are at the same line (it changed when I pasted it here)

Code:

# This file uses centimeters as units for non-parametric coordinates.

mtllib box.mtl
g default
v -0.500000 -0.500000 0.500000
v 0.500000 -0.500000 0.500000
v -0.500000 0.500000 0.500000
v 0.500000 0.500000 0.500000
v -0.500000 0.500000 -0.500000
v 0.500000 0.500000 -0.500000
v -0.500000 -0.500000 -0.500000
v 0.500000 -0.500000 -0.500000
vt 0.000000 0.000000
vt 1.000000 0.000000
vt 0.000000 1.000000
vt 1.000000 1.000000
vt 0.000000 2.000000
vt 1.000000 2.000000
vt 0.000000 3.000000
vt 1.000000 3.000000
vt 0.000000 4.000000
vt 1.000000 4.000000
vt 2.000000 0.000000
vt 2.000000 1.000000
vt -1.000000 0.000000
vt -1.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 0.000000 1.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 0.000000 -1.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 0.000000 -1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
vn -1.000000 0.000000 0.000000
s off
g pCube1
f 1/1/1 2/2/2 4/4/3 3/3/4
f 3/3/5 4/4/6 6/6/7 5/5/8
f 5/5/9 6/6/10 8/8/11 7/7/12
f 7/7/13 8/8/14 2/10/15 1/9/16
f 2/2/17 8/11/18 6/12/19 4/4/20
f 7/13/21 1/1/22 3/3/23 5/14/24

Quote:

I'm not certain, but I think you could actually read the floats directly from a file such as;

Code:

float getcord;

ifstream in("model.obj", ios::in | ios::binary)
in>>getcord;

I'd dump the comma separator, btw. Just use a space. Some use the comma as a decimal point, so that can get confusing -
That did not work very well. When I tried to output the numbers again I got things like 1.#### and so on, which did not make sense.

Right now im experimenting with sscanf, not sure if its the right thing or not, but at least I can do things like this:
sscanf(file, float, float, float).

But right now it does not read the numbers correct.

• 05-10-2007
Salem
> while (! myFile.eof())
See the FAQ as to why using eof in a control loop is bad.

Use
while ( getline(myFile, currentLine) )

> if (currentLine[0] == 'V')
None of your input begins with upper case V ?

Personally, I'd go with
Code:

while ( getline(myFile, currentLine) ) {
if ( currentLine[0] == 'V' ) {
processVertex( currentLine );
} else {
// unknown line type?
}
}

Don't try to do too much in the same function, break it up into functions which perform very specific tasks.
• 05-10-2007
h3ro
Thank you Salem, I changed it a bit now, so I don't have so long code. But I am still struggling with how to read the numbers efficiently.
• 05-10-2007
h3ro
hallo,

Now I have something working here, but I would very much like some input on it. Is this a good way to do it?

Code:

Vector3D processVertex(std::string line);

{
std::string currentLine;            // Variable that holds the current line
// we are using.
std::vector<Vector3D> vertexList;  // A dynamic vector array for holding
// the info about the vertexs

// Open file
std::ifstream myFile (FileName);
if (myFile.is_open())
{
// While the file is open, we read the info and construct triangles
while ( getline(myFile, currentLine) )
{
// Check if this line holds vertex information. If the line starts
// with "v ", we will use it.
if (currentLine[0] == 'v' && currentLine[1] == ' ' )
{
vertexList.push_back(processVertex(currentLine));
}

// Check if the line holds uv information. If its starts with
// "vt" if a uv.
if (currentLine[0] == 'v' && currentLine[1] == 't')
{
}

// Check if the line holds normal information. If its starts with
// "vn" if a normal.
if (currentLine[0] == 'v' && currentLine[1] == 'n')
{
}

}
// Finished with reading the file, close it
myFile.close();
}

// Temp, without it, the program crashes
std::vector <Triangle> myVar;

return myVar;
}

Vector3D processVertex(std::string line)
{
std::string vertexString[3];

for (int x = 0; x < 3; x++)
{
for (int i = 2; i <= line.size(); i++)
{
//Break up the string into the three cordinates
if ( line[i] != ' ')
{
vertexString[x].push_back(line[i]);
}
}
}

// Convert the string into a number
Vector3D vertex( (float)atof(vertexString[0].c_str()),
(float)atof(vertexString[1].c_str()),
(float)atof(vertexString[2].c_str())
);

return vertex;
}

• 05-10-2007
Daved
I would use a stringstream inside processVertex. You can read each value into a float variable directly. An istringstream constructed with your line variable will work just like an ifstream or cin, so it shouldn't be that hard to use.

Is there a reason you're not using double, the default floating-point typein C++, instead of float?
• 05-10-2007
h3ro
Quote:

Is there a reason you're not using double, the default floating-point typein C++, instead of float?
The only reason is that Vector3D takes floats, so its just the easiest to do.