【问题标题】:Reading a structured file读取结构化文件
【发布时间】:2018-09-19 11:17:55
【问题描述】:

我编写了这个小程序来从 txt 文件中读取Orders:

struct Date
{
    int year;
    int month;
    int day;
};

istream& operator>>(istream& is, Date& d)
{
    int dd, m, y;
    char slash1, slash2;
    is >> dd >> slash1 >> m >> slash2 >> y;
    d.day = dd;
    d.month = m;
    d.year = y;
    return is;
}

class Purchase
{
public:
    string product_name;
    double unit_price;
    int count;
};

istream& operator>>(istream& is, Purchase& p)
{
    string pd;
    double price;
    int cnt;
    is >> pd >> price >> cnt;
    if (!is)
    {
        is.unget();
        is.clear(ios_base::failbit);
        return is;
    }
    p.product_name = pd;
    p.unit_price = price;
    p.count = cnt;
    return is;
}

struct Address
{
    string add;
};

istream& operator>>(istream& is, Address& a)
{
    string s;
    string aa;
    while (true)
    {
        is >> aa;
        s = s + aa + ' ';
        if (s[s.length() - 2] == '.')break;
    }
    a.add = s;
    return is;
}


class Order
{
public:
    string name;
    Address address;
    Date dt;
    vector<Purchase>purch;
};


istream& operator>>(istream& is, Order& o)
{

    string nm;
    Address aa;
    Date dd;

    is >> nm>> aa >> dd;
    if (!is)
    {
        is.unget();
        is.clear(ios_base::failbit);
        return is;
    }
    o.name = nm;
    o.address.add = aa.add;
    o.dt.day = dd.day;
    o.dt.month = dd.month;
    o.dt.year = dd.year;

    for (Purchase pp; is >> pp;)
    {
        o.purch.push_back(pp);
    }
    return is;
}

文本文件格式如下:

John
3, Apple Street, Lagos.
11/3/2018
Soap    100 2
Cream   250 1
Cheese  50  6

Matthew
10, Orange Street, Milan.   
10/1/2018   
Tissue  50  2
Cookies 10  5
Shirts  500 2
Pen 35  1

main函数中测试这个程序时:

int main()
{
    cout << "Enter input file name: ";
    string input_file;
    cin >> input_file;
    ifstream ifs{ input_file };

    vector<Order>ord;

    while (true)
    {
        Order g;
        if (!ifs)break;
        ifs >> g;
        ord.push_back(g);
    }

    cout << ord[0].name << endl;
    cout << ord[0].address.add << endl;
    cout << ord[0].dt.year << endl;
    cout << ord[0].purch[0].count << endl;
    cout << endl;
}

我发现它只将Order 的第一个实例读入ord 向量。 ifstream ifs 在第二次尝试读取新的Order 时失败并爆发。所以在上面的示例文件中,我只能成功读取 John 的订单。现在我被困住了,我需要帮助。谢谢。

【问题讨论】:

  • 您只打印一份订单(即ord[0]
  • @codekaizer 我就这样离开了,因为这是唯一有效的下标...当我打印ord[1]时,它说向量下标超出范围@
  • for (Purchase pp; is &gt;&gt; pp;) 循环在消耗整个文件之前不会终止。
  • @IgorTandetnik 我也试过这个循环来阅读Purchasewhile (true) { Purchase pp; if (!(is &gt;&gt; pp))break; o.purch.push_back(pp); }
  • (is &gt;&gt; pp) 只会在eof 上变为false(在布尔上下文中),因为您在返回之前明确清除了failbit。支票的任何洗牌都不会改变这一事实。

标签: c++ c++11 file-io io iostream


【解决方案1】:

如果您将for (Purchase pp; is &gt;&gt; pp;) 替换为

int i = 0;
for (Purchase pp; is >> pp && i++ < 3;)

您可以看到代码运行有点正常。

但是,这会产生购买规模可变的问题。循环常数的大小应该是多少? 我建议在每个对象末尾的数据中使用 sentinel,例如“1”。然后可以将循环修改为:

for (Purchase pp; is.peek() != 1 &amp;&amp; is &gt;&gt; pp;)

另外,不要忘记在循环结束后杀死下一个字符(它将是'1')

char c; is &gt;&gt; c;

【讨论】:

    【解决方案2】:

    感谢@GillBates 的哨兵想法和@IgorTandetnik 揭露我代码中的错误部分。我能够通过在每个订单的开头使用整数索引来纠正这个问题,然后在 operator>>Order 函数的末尾添加 is.clear()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-31
      • 1970-01-01
      • 2015-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多