C ++将带有分隔符的文本文件读入struct数组 [英] C++ Reading text file with delimiter into struct array

查看:39
本文介绍了C ++将带有分隔符的文本文件读入struct数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试从格式与此类似的文本文件中读取数据:

 刀,物件,0包,物件,15厨房,房间,400 

放入由结构组成的数组.这是我到目前为止的内容,但是它只读取第一个元素,然后返回垃圾.

  #include< iostream>#include< fstream>#include< string>使用命名空间std;结构项目清单{字符串类型;字符串卖出类型;整数价格;int diditsell = 0;};int main(){字符串文件名;cout<<请输入文件名."<<恩德尔cin>>文件名;ifstream in(文件名);项目清单c [100];为(int i = 0; i< 100; i ++){在>>中c [i] .type>>c [i] .selltype>>c [i] .price;cout<<c [i] .type<<恩德尔cout<<c [i] .selltype<<恩德尔cout<<c [i] .price<<恩德尔}} 

我试图找到一些特别适合我尝试执行的示例,但是实施这些示例并不能解决问题.任何帮助将不胜感激.

解决方案

可见问题的症结在于

for(int i = 0; i< 100; i ++)

将打印出整个100个元素的数组,无论文件中是否有要加载到数组中的数据.

可能最简单的方法使用 std :: vector .这是一个动态大小的数组.当您添加它时,它会变大,因此您不必担心它会溢出.最后,我们将继续讨论.

接下来要做的就是确保您已成功读取文件.可以对流进行测试以查看它们是否有效.

 如果(输入){cout<<好!"<<恩德尔} 

>> 运算符返回对该流的引用,以便您可以

  if(在>>数据中){cout<<数据很好!"<<恩德尔} 

如果读取数据后流仍然良好,则您至少知道文件将某些内容读取到了正确类型的数据中,或者可以将其转换为正确类型.您应该自己检查一下读入后的值,以确保用户没有打错字或不致使程序崩溃.如果您想遍历很多东西(例如文件),那么您会遇到类似这样的事情:

  while(在>> c [i] .type>> c [i] .selltype>>> c [i] .price中) 

如果任何读取失败,则流在测试时将返回false,并且循环将退出.

查看源数据,您需要处理空格和逗号.>> 仅知道如何处理空格,除非您要做很多额外的工作.您将读到的是

 刀,目的,0 

,我们不需要逗号.幸运的是,它是最后一个字符,因此处理起来很容易.可以使用 C ++ 11 std :: string 像堆栈一样使用,您可以弹出不需要的字符:

  c [i] .type.pop_back();c [i] .selltype.pop_back(); 

总的来说,这给了我们一个看起来像循环的

  ifstream in(文件名);项目清单c [100];int i = 0;同时(在>> c [i] .type>> c [i] .selltype>>> c [i] .price中){c [i] .type.pop_back();c [i] .selltype.pop_back();cout<<c [i] .type<<恩德尔cout<<c [i] .selltype<<恩德尔cout<<c [i] .price<<恩德尔i ++;} 

但这会超出100个元素数组的末尾,因此我们需要稍微更改 while 循环:

  while(i< 100&>中c [i] .type>> c [i] .selltype>> c [i] .price) 

如果 i 大于或等于100,则 i<100 大小写失败,并且甚至不尝试>>中的c [i] .type>>c [i] .selltype>>c [i] .price 并写入不存在的阵列插槽.

请记住要保留 i 的值,因为数组很笨.他们不知道他们有多饱.

但是使用 vector ,您不需要 i 进行计数或跟踪其填充量,也无需担心数组溢出直到计算机的RAM耗尽.我们需要做的是读取一个临时变量,我们很高兴.

  vector< itemlist>C;项目清单温度;同时(在>>临时类型>>临时销售类型>>临时价格中){temp.type.pop_back();temp.selltype.pop_back();cout<<临时类型<<恩德尔cout<<temp.selltype<<恩德尔cout<<临时价格<<恩德尔c.push_back(temp);} 

I am trying to read data from a text file formatted similarly to this:

knife, object, 0
bag, object, 15
kitchen, room, 400

Into an array composed of structures. Here is what I have so far, but it only reads the first element then returns garbage.

#include <iostream>
#include <fstream>
#include <string>


using namespace std;

struct itemlist
{
  string type;
  string selltype;
  int price;
  int diditsell=0;
};

int main()
{
  string filename;
  cout << "Please enter a file name. " << endl;
  cin >> filename;

  ifstream in(filename);
  itemlist c[100];
  for (int i=0;i<100;i++)
  {
      in >> c[i].type >> c[i].selltype >> c[i].price;
      cout << c[i].type << endl;
      cout << c[i].selltype << endl;
      cout << c[i].price << endl;
  }
}

I have tried to find examples that specifically suit what I am trying to do but implementing them has not fixed the problem. Any help would be greatly appreciated.

解决方案

The crux of the visible problem is that with

 for (int i=0;i<100;i++)

the entire 100 element array will be printed out whether there was data in the file to be loaded into the array or not.

Probably the easiest way to do this is with a std::vector. It's a dynamically sized array. As you add to it it gets bigger so you don't have to worry about it overflowing. We'll get back to it at the end.

The next thing you have to do is make sure you're reading the file successfully. Streams can be tested to see if they are valid.

if (in)
{
    cout << "in is good!" << endl;
}

and the >> operator returns a reference to the stream so you can

if (in >> data)
{
    cout << "data is good!" << endl;
}

If the stream is still good after reading data, you know that at the very least the file read something into data that was of the correct type or could be converted into the correct type. You owe it to yourself to check the value read after reading it in to make sure the user didn't typo or go out of their way to crash the program. If you want to loop through a lot of stuff, like a file, you wind up with something like this:

while (in >> c[i].type >> c[i].selltype >> c[i].price)

If any of the reads failed the the stream will return false when tested and the loop will exit.

Looking at your source data you have spaces and commas to deal with. >> only knows how to deal with spaces unless you're going to do a lot of extra work. What you will read in is

knife,
object,
0

and we don't want the comma. Fortunately, it's the last character so dealing with it is easy. A C++11 std::string can be used like a stack and you can just pop the unwanted character off:

c[i].type.pop_back();
c[i].selltype.pop_back();

All together, this gives us a loop that looks like

ifstream in(filename);
itemlist c[100];
int i = 0;
while (in >> c[i].type >> c[i].selltype >> c[i].price)
{
    c[i].type.pop_back();
    c[i].selltype.pop_back();
    cout << c[i].type << endl;
    cout << c[i].selltype << endl;
    cout << c[i].price << endl;
    i++;
}

but this can overrun the end of the 100 element array, so we need to change the while loop slightly:

while (i < 100 && in >> c[i].type >> c[i].selltype >> c[i].price )

If i is greater than or equal to 100, the i < 100 case fails and the loop exits without even trying in >> c[i].type >> c[i].selltype >> c[i].price and writing into the non-existent array slot.

Remember to keep the value of i around because arrays are dumb. They don't know how full they are.

But with a vector you don't need i to count or to keep track of how full it is and you don't need to worry about overflowing the array until you run your computer out of RAM. What we do need is one temporary variable to read into and we're good to go.

vector<itemlist> c;
itemlist temp;
while (in >> temp.type >> temp.selltype >> temp.price)
{
    temp.type.pop_back();
    temp.selltype.pop_back();
    cout << temp.type << endl;
    cout << temp.selltype << endl;
    cout << temp.price << endl;
    c.push_back(temp);
}

这篇关于C ++将带有分隔符的文本文件读入struct数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆