Click here to Skip to main content
15,891,033 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi Everyone,

I'm trying to loop through a text file so that I can print the content out in a re-ordered way. I have the following code, which works fine, however when it comes to fprintf I can only loop to a fixed number of rows, which is currently 16 for my text environment. Can someone help me loop to the end of the file as I don't know how to. I don't know how many lines will be in the text file, but can be in the hundreds of thousands.

C++
// CProgtest.cpp : main project file.
#include <stdAfx.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
int main()
{
    char line[200];
    int i = 0;
    long NodeName[50];
    double x[50];
    double y[50];
    double z [50];

    FILE *pFile, *sacsout;
    pFile = fopen("ASASIN.txt", "r");
    //fgets gets a string from a file//one string per line
    while(fgets(line, sizeof line, pFile) != NULL)
    {
    if(sscanf_s(line, "%d %lf %lf %lf", &NodeName[i], &x[i], &y[i], &z[i]) == 4)
        {
            ++i;
        }
    }
    //Close the file


    if( (sacsout = fopen("Sacs1.inp", "w" )) != NULL )
    {
    }
    else
    {printf( "Problem creating SACS Output file\n");}

    for (i = 0; i < 16; i++)

    fprintf(sacsout,"%d %lf %lf %lf\n", NodeName[i], x[i], y[i], z[i]);
    /*{
    ++i;
    }    */
    fclose(pFile);
    fclose (sacsout);
}
Posted
Updated 26-Apr-13 3:17am
v2
Comments
Ian A Davidson 26-Apr-13 14:03pm    
Could you clarify what you mean, please, by only being able to loop to a fixed number of rows? Are you trying to display 16 lines at a time on screen, or do you want to create more than one file with 16 lines in each?
Regards,
Ian.
Member 9357265 30-Apr-13 9:21am    
Hi Ian,
Apologies for only returning now..

A sample of the file being read is as follows. The first column is nodename, the second X, Third Y, Fourth Z. I've only shown 16 lines as per the code, but there could be thousands of lines, unknown at this time.

101010 -34.9000 -28.7500 -101.0000
101030 -13.0000 -28.7500 -101.0000
101070 13.0000 -28.7500 -101.0000
101090 34.9000 -28.7500 -101.0000
102410 -34.9000 -19.0000 -101.0000
102430 -13.0000 -19.0000 -101.0000
103630 -13.0000 -10.0000 -101.0000
105010 -34.9000 0.0000 -101.0000
105030 -13.0000 0.0000 -101.0000
105070 13.0000 0.0000 -101.0000
105090 34.9000 0.0000 -101.0000
106430 -13.0000 10.0000 -101.0000
109010 -34.9000 28.7500 -101.0000
109030 -13.0000 28.7500 -101.0000
109070 13.0000 28.7500 -101.0000
109090 34.9000 28.7500 -101.0000

Besides what Jochen pointed out in his solution 1, the biggest problem with your code is that you are buffering the input in various arrays of fixed size, 50 at the moment. These are NodeName, x, y, and z. As long as these array have a fixed capacity of 50 you will not be able to read files with more than 50 lines.

The solution to this is: First determine the number of lines in your file. Then go back to the beginning. Now allocate your arrays dynamically with new or by using std::vector. And finally read the file again and parse the lines into your arrays.

Better yet: Use the above approach, but these variables into a structure and then allocate an array of these structures, either with new or std::vector<mystructure>. That simplifies looping and you always have all data belong to one object in a structure. This will simplifiy argument passing when your program is being expanded.

[AMENDED]

Ok, let me explain a little more detailed. First I would define a structure that hold all the data of a single line. For example:
C++
struct Node
{
   long name;
   double x, y, z;
};

To store an arbitrary number of such structures you could use an STL vector. Here is how you would define that:
C++
#include <vector> // at the beginning of your .cpp file
...
std::vector<Node> nodes;

To access the 5th such node you would simply write: nodes[4]. Of course you have to tell the array, for how many nodes it should allocate storage. That is done by calling the resize function:
C++
nodes.resize (1000);

This would allocate 1000 structures of type Node. The problem is that you don't know how many nodes you need until you have read the entire file. You could call resize before reading the next record of your file, each time with a number that is 1 higher than the previous time. Another way is to use the push_back function, which appends just one more structure to the end of the array. So your loop would look like this:
C++
while (fgets(line, sizeof line, pFile) != NULL)
{
    Node newNode;
    int cntRead = sscanf_s(line, "%d %lf %lf %lf",
        &newNode.name[i], &newNode.x[i], &newNode.y[i], &newNode.z[i]);
    if (cntRead != 4)
    {
        ... output error message
        return -1; // line has illegal format
    }
    nodes.push_back (newNode);
}

After having read the entire file you can now access your nodes in arbitrary order. For example a backwards loop would look like:
C++
for (int idx = (int) nodes.size() - 1; idx >= 0; --idx)
{
    const Node& node = nodes[idx];
    // ... do something with node
}

I hope that gives you an idea on how to proceed.

BTW, if you only want to re-order the lines in that file, you don't have to parse it with sscanf. Simply store the lines of your file in a vector, must like shown above, and then output those lines in reverse order. I leave that as a little exercise for you.
 
Share this answer
 
v2
Comments
Member 9357265 30-Apr-13 9:25am    
Hi nv3 (And Jochen), thanks both for your input, much appreciated. I'm quite new to c++ and like the sound of the structure, but am a little lost in the code. Would it be possible for you to give me a snippet of what you mean?
nv3 30-Apr-13 13:51pm    
See the amendement to my solution above.
Member 9357265 3-May-13 8:05am    
Thanks nv3. I've managed to achieve what I wanted to do without using the structures, but I do want to have another look at it when I get the time... thanks for the help thusfar.
nv3 3-May-13 8:42am    
Welcome!
When reading data from the file, you are counting the lines using the variable i. Because your buffers have a size of 50, you should also check this here:
while( i < 50 && fgets(line, sizeof line, pFile) != NULL)
// Or better:
while( i < sizeof(x) / sizeof(x[0]) && fgets(line, sizeof line, pFile) != NULL)


But the real problem is that you are re-using i in the output loop. Just use another variable letting i unchanged or save the number of lines:
C++
int nLines = i;
for (i = 0; i < nLines; i++)
    fprintf(sacsout,"%d %lf %lf %lf\n", NodeName[i], x[i], y[i], z[i]);
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900