简体   繁体   中英

Trouble reading file using getline (noob)

I'm a noob C++ student. I'm having trouble reading a file into a array structure. This is a class assignment so I do not need any one to do the code for me, I just want to know what I'm doing wrong. The text file I'm reading is formatted as such:

Giant Armadillo#443#M
Hawaiian Monk Seal#711#M 
Iberian Lynx#134#M
Javan Rhinoceros#134#M etc...

Using getline() works correctly reading the string with a '#' delimiter, but does not work with the int or the char . How do I read an int or char while checking delimiters? Thanks, sorry if this isn't written clearly, or formatted properly. I'm brand new to SO.

#include <iostream>
#include<string>
#include <fstream>
#include <cstdlib>
using namespace std;

//Create a new structure
struct Endangered
{   
    string name;
    int population; 
    char species;
};


int main () {

Endangered animals[200];

//initialize animals
for (int i=0; i<50; i++)
{
    animals[i].name=" ";
    animals[i].population=0;
    animals[i].species=' ';
}

ifstream myFile;
myFile.open("animals.txt");
int i=0;
if (myFile.is_open())
{   
    while (myFile.eof())
    {   
        //read the string until delimiter #
        getline(myFile, animals[i].name, '#');

        //read the int until delimiter #
        getline(myFile, animals[i].population, '#');

        //read the char until the delimiter
        getline(myFile, animals[i].species, '/n');
        i++;
    }


    return 0;
}

I'm sure you cannot read data from file like this:

//read the int until delimiter #
getline(myFile, animals[i].population, '#');

because you got sting and you want to assign it to int or char field.

look at this declaration:

istream& getline (istream& is, string& str, char delim);

you have to have string as a second argument. You cannot pass to this function int or char and animals[i].population is typeof int.

You should first load data to some string or char* buffer and then use correct functions to convert it to type you want. look for functions like atoi for example.

To sum up. Read data to temporary buffer and then convert it.

If that doesn't help you I'll correct the code but you didn't want to :)

The read part of your program can look like this:

size_t i=0;
ifstream myFile("animals.txt");
if(!myFile)
{
  throw std::runtime_error("Failed opening file");   
}
string line;
while(std::getline(myFile, line))
{
  istringstream line_stream(line);
  string temp;
  if(!std::getline(line_stream, temp, '#'))
    throw std::runtime_error("expected #");
  animals[i].name = std::stoi(temp);

  if(!std::getline(line_stream, temp, '#'))
    throw std::runtime_error(expected #");

  animals[i].population = std::stoi(temp);

  if(!std::getline(line_stream, temp) || temp.size() != 1) // or whatever input verification you need
    throw std::runtime_error("expected species");
  animals[i].species = temp[0]; // or whatever input you need, this assumes species is a char
}

There are ways without all the buffering done here, but this should work.

The problem is that the getLine function returns the next delimited value as a string: Function def: getline (istream& is, string& str, char delim);

Change your code to read the values into a temporary string variable.

Then use std::stoi( str ) to convert the string value into an integer and assign the returned value to population.

You requested that no code be supplied, so I will leave the implementation up to you.

Hope this helps.

There are two problems here: reading non-space delimited text (strings containing spaces) and converting text into numbers.

The quick and dirty way can be:

for(int i=0; myFile && i<sizeof(animals)/sizeof(Endangered); ++i)
{   
    char delim = 0; 

    //read the string until delimiter #
    getline(myFile, animals[i].name, '#');

    //read the int 
    myfile >> animals[i].population;
    //read and check delimiter
    if(myfile>>delim && delim!='#') mifile.setstate(myfile.failbit);

    //read the species
    myfile >> animals[i].species;

    //discard any other rubbish untile the end of line
    myfile.ignore(std::numeric_limits<std::streamsize>::max(),'\n');
    myfile >> delim; // this is '\n';
}

Note that:

  • I used for (not while) so that the counter ( i ) and its increment ( ++i ) are defined together (nmo risk to forgot).

  • The exit condition is not myfile.eof() (when it happens it is already too late), by just myfile (it can self- convert into "true" if "readable": you exit if the file becomes unreadable, for whatever error, even if not yet at end )

  • another exit condition (in && with the first) is that the array had been completely filled (the expression is just its size, whatever it is)

    • The first string (may contain spaces) is read up to '#' (that is read, but not stored, just as you neeed)

    • The number is read as an input filed (if there is no number, the >> operator will set the failbit, and you will no more read and safely exit)

    • The delimiter is read as an input field: any space after the number and before the # is discarded. # goes into delim , and if we found it is not a #, we set the failbit (the file does not contain what is supposed to contain) and block any read and safely exit the loop (myfile wil evaluateas false).

    • Every eventual space is discarded, and the next character goes into species .

    • Now lets discard anything eventually remain on the line (including the '\\n').

    • We can now proceed with the next line.

Note that your wrapping if is not needed: if myfile did not open, it evaluate as "false" and the loop will not be entered.

The eof() condition, here, must not be seen as "the failure that terminats" but the "reached succes".

if -after the loop- file.eof() is true, you successfully read all, otherwise you stopped prematurely because of an error.

Note also that the entire for body can be the body of a function named

std::isream& operator>>(std::istream& myfile, Endangered& endangered)
{
  .....
  .....
  return myfile;
}

and the loop will be just

for(int i=0; myFile && i<sizeof(animals)/sizeof(Endangered); ++i)
   myfile >> animals[i];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM