4

I have a text file, that is formatted somewhat like this:

1 3 4 5 6
6 7 8
4 12 16 17 18 19 20
20
0

A line can contain 1 to 10000 integers. What I need to do, is read all of them line by line.

Pseudocode like this:

line=0;
i=0;
while(!file.eof()){
 while(!endLine){

 array[0][i++]=file.readChar();
 }
line++;i=0;
}

So, I have an array , into which I would like to read every line, and each line would consist of each of these integers.

The problem I'm having, is how to check if the end of a line has come.

Note, I can't use strings.

Yes, This is for a homework, but the main task for the assignment is to build a tree and then transform it. I can do that, but I've no idea how to read the integers from the file.

Janis Peisenieks
  • 4,938
  • 10
  • 55
  • 85

4 Answers4

4

Probably something like this:

after reading an int, I manually skip spaces, tabs, carriage return and end of line (for this one you'll have to implement your logic). To read an int I read it directly using the C++ functions of ifstream. I don't read it character by character and then recompose it as a string :-) Note that I skip \r as "spaces. The end of line for me is \n.

#include <iostream>
#include <fstream>
#include <vector>

int main() 
{
    std::ifstream file("example.txt");

    std::vector<std::vector<int>> ints;

    bool insertNewLine = true;

    int oneInt;

    //The good() here is used to check the status of 
    //the opening of file and for the failures of
    //peek() and read() (used later to skip characters).
    while (file.good() && file >> oneInt)
    {
        if (insertNewLine)
        {
            std::vector<int> vc;
            ints.push_back(vc); 

            //With C++11 you can do this instead of the push_back
            //ints.emplace_back(std::vector<int>());

            insertNewLine = false;
        }

        ints.back().push_back(oneInt);

        std::cout << oneInt << " ";

        int ch;

        while ((ch = file.peek()) != std::char_traits<char>::eof())
        {
            if (ch == ' '|| ch == '\t' || ch == '\r' || ch == '\n')
            {
                char ch2;

                if (!file.read(&ch2, 1))
                {
                    break;
                }

                if (ch == '\n' && !insertNewLine)
                {
                    std::cout << std::endl;
                    insertNewLine = true;
                }
            }
            else
            {
                break;
            }
        }
    }

    //Here we should probably check if we exited for eof (good)
    //or for other file errors (bad! bad! bad!)

    return 0;
}
xanatos
  • 109,618
  • 12
  • 197
  • 280
  • More of a 'C' answer than 'C++' in terms of structure (you could easily replace std::ifstream with FILE*) - you should encapsulate the parsing logic and the tree building logic into classes to make it really C++! – Skizz Oct 19 '11 at 10:47
  • 1
    `while(!myfile.eof())` Very, very BAD!! Search SO for why. – Xeo Oct 19 '11 at 10:52
  • Since the last file in my input file would ALWAYS be a single 0, and 0 can't appear anywhere else, I just replaced it with `while(myInt!=0)` – Janis Peisenieks Oct 19 '11 at 10:56
  • @Xeo Yeah... I had forgotten. It was more complex to find the SO article :-) now I use `good`. – xanatos Oct 19 '11 at 11:06
  • @xanatos: Same problem, `good` will also only be changed after a failing read. Search my answers, I can't as of right now because I'm writing from my iPhone. – Xeo Oct 19 '11 at 11:32
  • @Xeo I check it at the beginning for errors in the opening of the file (and errors for the consuming of spaces from the previous cycle) *and* after each read with `>>`/`peek`. Where is the problem? The only thing I could see would be a `peek` with no error + a `read` of that byte with error. Then I would do a new `peek` without rechecking for the error. Should I recheck the `good()` after the `read`? – xanatos Oct 19 '11 at 11:39
  • Just use the normal idiom `while(myfile >> myInt)`. No need for double and tripple checks with that. I'd explain it better if I wasn't on my iPhone. – Xeo Oct 19 '11 at 12:30
  • @Xeo What I don't remember is if !good is "sticky" or not. If (for example) there is a transient error, and I do a `>>` (that fails), can I have a successive `>>` that succeeds? Are the error recoverable? Or do I need to close the stream and reopen it? – xanatos Oct 19 '11 at 12:33
2

There is a function called getline() which will read a whole line. Link

v01d
  • 1,457
  • 1
  • 11
  • 22
  • The OP said `Note, I can't use strings.` – Skizz Oct 19 '11 at 10:22
  • The getline() function returns char* not a string. – v01d Oct 19 '11 at 10:24
  • @Skizz: Who said that you need to use `std::string` with `getline()`? If you follow the link you will see that the answer refers to `istream::getline` that takes a plain `char*` and size – David Rodríguez - dribeas Oct 19 '11 at 10:27
  • 1
    Also, getline requires an array to be allocated and passed in, which means the maximum line length needs to be pre-defined. Otherwise, you might split a line in half (worse, split a number in half!) – Skizz Oct 19 '11 at 10:28
  • Why do you assume the OP means std::string? getline gives you a nul-terminated sequence of chars, commonly known as a string. – Skizz Oct 19 '11 at 10:31
  • Yes but not in terms of C++, which has a string type. And as a student the rule to not use string is meant to be the c++ type string not a so called c-string. – v01d Oct 19 '11 at 10:33
0

You need a function to read a value from a file or indicates an end of line or end of file condition, something like:

result_type GetNextValue (input_file, &value)
{
  if next thing in file is a number, set value and return number_type
  if next thing in file is an end of line, return end_of_line_type
  if end of file found, return end_of_file_type
}

and then your array building loop becomes:

line = 0
item = 0
eof = false

while (!eof)
{
  switch (GetNextValue (input_file, value))
  {
  case value_type: 
    array [line][item++] = value

  case end_of_line_type:
    line++;
    item = 0;

  case end_of_file_type:
    eof = true
  }
}

I'll leave the details to you as it's homework.

Skizz
  • 69,698
  • 10
  • 71
  • 108
  • Yes, but HOW DO I CHECK IF THE END OF LINE HAS COME? `if next thing in file is an end of line, return end_of_line_type`, how do I check for this? – Janis Peisenieks Oct 19 '11 at 10:32
  • @JanisPeisenieks: As you read the file one character at a time, you either get a number, a space or an end-of-line character. End of line characters are a pain because some systems use 0x0a followed by 0x0d, some do it the other way round and some just one of them. The GetNextValue needs to contain state information about what it's read so far. Better still, as you're using C++, it needs to be an object with the input_file as a constructor argument and the GetNextValue as a member function (no need to pass in any parameters this way) and an additional GetReadValue. – Skizz Oct 19 '11 at 10:39
0

You could read the numbers in a char and check against carriage return. A snippet that I had just tried is given below:

ifstream ifile;  
ifile.open("a.txt");  
char ch;  
while((ch = ifile.get()) != EOF)  
{  
    std::cout<<ch<<"\n";  
    if (ch == '\n')  
        std::cout<<"Got New Line";  
}  
ifile.close();  
g4th
  • 983
  • 9
  • 14