2013-05-19 99 views
-1

我试图从文件读取我的数据库。从文件C++读取数据库

这里是我的save_base方法:

void data_base::save_base() 
{ 
    fstream file; 

    file.open("base.dat", ios::in | ios::out | ios::trunc); 

    if(file.good()==true) { 
     node *p = new node(); 
     p=first; 

     while(p) { 
      file << p->content->connect() << ";" << "\n"; 
      p=p->next; 
     } 
     file.close(); 
    }else{ 
    cout << "Err - opening file." << endl; 
    } 
} 

连接方法:

string product::connect() { 

    ostringstream do_string; 
    do_string << lp; 
    string new_lp = do_string.str(); 

    ostringstream do_string1; 
    do_string1 << count; 
    string new_count = do_string1.str(); 

    ostringstream do_string2; 
    do_string2 << prize; 
    string new_prize = do_string2.str(); 

    ostringstream do_string3; 
    do_string3 << vat; 
    string new_vat = do_string3.str(); 

    string connected = type + ";" + new_lp + ";" + name + ";" + new_count + ";" + unit + ";" + new_prize + ";" + new_vat; 
    return connected; 
} 

和read_base方法:

void data_base::read_base() 
{ 
    fstream file; 

    file.open("base.dat", ios::in); 
    if(file.good()==true) 
    { 
     char data_row[50]; 
     int i=1; 
     while(!file.eof()) { 
      file.getline(data_row,100); 

     string data_content[50]; 
     int j = 0; 

     char *buff; 
     buff = strtok (data_row,";"); 
     while (buff != NULL) { 
      data_content[j] = buff; 
      buff = strtok (NULL, ";"); 
      j++; 
     } 
     string type = data_content[0]; 
     int lp; 
     istringstream iss1(data_content[1]); 
     iss1 >> lp; 
     double count; 
     istringstream iss2(data_content[3]); 
     iss2 >> count; 
     double prize; 
     istringstream iss3(data_content[5]); 
     iss3 >> prize; 
     double vat; 
     istringstream iss4(data_content[5]); 
     iss4 >> vat; 

     // Sprawdzamy typ obiektu zapisanego w danym wierszu pliku 
     if(type == "product") 
     { 

      product new_prod(lp, data_content[2], count, data_content[4], prize, vat); 
      product *new_product = new product(new_prod); 
      this->add(new_product); 
     } 
     i++; 
     } 
    file.close(); 
    }else{ 
     cout << "Err opening file." << endl; 
    } 
} 

我加入一些产品数据库,它工作正常。即使保存到文件也很好。但主要问题是当我试图从文件读取数据库。从文件读取数据库工作正常,但最终,应用程序不会自行结束。我认为还有一些缓冲需要结束。但我不知道它们是靠近哪个或靠近的。

+1

所以,当你看着你的调试器,如果应用程序没有结束,应用程序停止在哪里? – Useless

+0

听起来像你的应用程序被困在无尽的循环中。在调试器中启动它,当你满意时,它处于卡住状态,“中断”应用程序的执行(Debug Menu-> Break All或类似的东西)。 –

+0

调用堆栈: #0 7755000D \t NTDLL LdrFindResource_U()(C:\ WINDOWS \ SYSTEM32 \ ntdll.dll中:??)! #1 775DF896 \t NTDLL RtlQueryTimeZoneInformation()(C:\ WINDOWS \ SYSTEM32 \ NTDLL。 dll:??) #2 74B4F499 \t ?? ()(??:??) #3 ?? \t ?? ()(??:??) –

回答

0

我看到至少有一个明显的错误,可能会产生未定义的行为。您正在分配50个字节但最多读取100个。

char data_row[50]; 
    int i=1; 
    while(!file.eof()) { 
     file.getline(data_row,100); 

我建议在此代码中将50更改为100。

+0

当他们需要访问超过100个字节时,他们再次获得UB。将其更改为'std :: string'并改为使用'std :: getline()'。 –

+0

@CaptainObvlious同意你的观点,但据我所知,没有'getline'重载接受'std :: string'。因此使用'std :: string'将涉及不止两个字符change =) –

+0

请参阅[std :: getline()](http://en.cppreference.com/w/cpp/string/basic_string/getline) –

1

老实说 - 你在这段代码中遇到了很多问题,我建议你的主要问题是你可能还在封装中摔角。你的代码使用了C和C++风格的组合,这些风格保证让代码难以阅读和维护,这就是为什么你在这里,人们都在努力给你答案。

这就是说,这个问题看起来像是在保存你调用的“新节点()”,看起来你会保存......没有。你不应该在产品中查询一些现有的价值吗?编辑:啊 - 不,你现在将它重新分配为“p = first”。那么你在前一行分配的节点会发生什么?

你也有一个潜在的堆栈撞时,你的任何行超过50个字节:

char data_row[50]; 
int i=1; 
while(!file.eof()) { 
    file.getline(data_row,100); 

如果你必须使用字符数组,进入自己使用的sizeof的习惯中:

file.getline(data_row, sizeof(data_row)); 

我花了一些时间来弄清楚istringstream是什么 - 你想把字符串转换成数字吗?比这更简单,更高效写成:

unsigned int lp = atoi(data_content[1].c_str()); 
or 
unsigned int lp = strtoul(data_content[1].c_str(), NULL, 10); 

你read_base功能,这是数据库的一部分,知道WAAAAY太多的数据记录。你需要让read_base看起来更像封装备案人口远:

void data_base::read_base() 
{ 
    fstream file("base.dat", ios::in); 
    if(file.good() == false) { 
     cout << "Error opening file." << endl; 
     return; 
    } 

    for(size_t rowNo = 0; !file.eof(); ++rowNo) { 
     row* row = data_type::make_object_from_row(file); 
     if(row != nullptr) 
      this->add(row); 
     } 
    } 
} 

您可能需要寻找到了“工厂模式”对如何实现data_row基本类型,可以让你做到这一点。但总之,您使产品继承data_type以便上述工作。 DATA_TYPE :: make_object_from_row会读取行的第一部分和枚举类型,以便它可以这样做:

data_type* data_type::make_object_row_row(istream& file) { 
    switch(get_type(file)) { 
     case DATA_TYPE_PRODUCT: return new product(file); 
     case DATA_TYPE_PERSON: return new person(file); 
     default: 
      clog << "invalid type in database: " << type << endl; 
      return nullptr; 
    } 
} 

(这只是一种可能的方法)。

+0

让我补充一句:如果您打算按照这种方式进行文字处理,您可能需要进一步研究[link](http://www.cplusplus.com/reference/string/string/getline/) 但是你可能还想看看你可以使用imbue()来告诉一个关于分隔符的流,以便知道要查找的方法;而不是空格,所以你可以这样做: 'product :: read(istream&file){... file >> lp >> name >> ...; }'和'product :: write(ostream&file){... file << lp << separator << name << separator << ...; }' – kfsone