【问题标题】:Trouble reading file using getline (noob)使用 getline (noob) 读取文件时遇到问题
【发布时间】:2013-03-27 11:59:41
【问题描述】:

我是一个菜鸟 C++ 学生。我无法将文件读入数组结构。这是一项课堂作业,所以我不需要任何人为我编写代码,我只想知道我做错了什么。我正在阅读的文本文件格式如下:

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

使用getline() 可以正确读取带有'#' 分隔符的字符串,但不适用于intchar。在检查分隔符时如何读取intchar? 谢谢,对不起,如果这不是写清楚,或格式不正确。我是 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;
}

【问题讨论】:

  • 使用'\n' 而不是'/n'

标签: c++ string syntax getline


【解决方案1】:

我确定你不能像这样从文件中读取数据:

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

因为你有 sting 并且你想将它分配给 int 或 char 字段。

看看这个声明:

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

您必须将字符串作为第二个参数。您不能将 int 或 char 传递给此函数,而 animals[i].population 是 int 类型。

您应该首先将数据加载到某个字符串或 char* 缓冲区,然后使用正确的函数将其转换为您想要的类型。例如,寻找像 atoi 这样的函数。

总结一下。将数据读取到临时缓冲区,然后进行转换。

如果这对您没有帮助,我会更正代码,但您不想这样做:)

【讨论】:

    【解决方案2】:

    程序的读取部分可能如下所示:

    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
    }
    

    有一些方法不需要在这里完成所有缓冲,但这应该可以。

    【讨论】:

      【解决方案3】:

      问题在于 getLine 函数将下一个分隔值作为字符串返回: 函数def: getline(istream& is, string& str, char delim);

      更改代码以将值读入临时字符串变量。

      然后使用std::stoi(str)将字符串值转换为整数,并将返回值赋给population。

      您要求不提供任何代码,所以我将把实现留给您。

      希望这会有所帮助。

      【讨论】:

        【解决方案4】:

        这里有两个问题:读取非空格分隔的文本(包含空格的字符串)和将文本转换为数字。

        快速而肮脏的方法可以是:

        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';
        }
        

        注意:

        • 我使用 for (not while) 以便一起定义计数器 (i) 及其增量 (++i)(nmo 忘记风险)。

        • 1234563无论错误如何,文件都变得不可读,即使还没有结束)
        • 另一个退出条件(在 && 与第一个)是数组已被完全填充(表达式只是它的大小,不管它是什么)

          • 第一个字符串(可能包含空格)被读取到 '#'(即读取,但不存储,就像您需要的那样)

          • 数字被读取为输入字段(如果没有数字,>>操作符将设置故障位,您将不再阅读并安全退出)

          • 分隔符被读取为输入字段:数字之后和 # 之前的任何空格都将被丢弃。 # 进入delim,如果我们发现它不是#,我们设置故障位(文件不包含应该包含的内容)并阻止任何读取并安全退出循环(myfile 将评估为假)。

          • 最终的每个空格都被丢弃,下一个字符进入species

          • 现在让我们丢弃最终保留在行中的任何内容(包括“\n”)。

          • 我们现在可以继续下一行了。

        请注意,不需要您的包装 if:如果 myfile 未打开,则评估为“false”并且不会进入循环。

        这里的 eof() 条件不能被视为“终止的失败”,而是“达到的成功”。

        如果-after the loop-file.eof() 为真,则说明全部读取成功,否则因错误提前停止。

        另请注意,整个 for 主体可以是名为

        的函数的主体
        std::isream& operator>>(std::istream& myfile, Endangered& endangered)
        {
          .....
          .....
          return myfile;
        }
        

        循环将只是

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

        【讨论】:

        • 这很有帮助。谢谢!!
        • 什么是'h' in: if(myfile>>h && h!='#') mifile.setstate(myfile.failbit);
        • @dana_muise:哎呀...一个错字:应该是delim。刚刚编辑。
        猜你喜欢
        • 2011-08-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-21
        • 2015-02-19
        相关资源
        最近更新 更多