при извлечении данных из файла; Я предпочитаю извлекать содержимое одной строки и сохранять его в какой-либо строке, потоке или буфере и анализировать его позже, или я получу все содержимое файла и сделаю то же самое. Мне легче разобрать строку после того, как вы извлекли данные из файла и закрыли его дескриптор. Я не люблю использовать глобальные переменные, которые НЕ являются CONST. Также то, как вы используете цикл for при чтении из файла while( file.eof() )
или while ( !file.eof() )
, является плохой практикой и может привести к множеству ошибок, сбоев и головных болей в дальнейшем. Если вы посмотрите на мою функцию ниже, все, что она делает, это берет имя файла и пытается открыть его, если оно существует. После того, как он откроется, он получит строку, сохранит ее в строку и вставит эту строку в вектор, пока больше не будет ничего для чтения. Затем он закрывает дескриптор файла и возвращает. Это соответствует концепции функции с единственной ответственностью.
Если у вас есть функция, в которой вы открываете файл, читаете строку, анализируете данные, читаете строку, анализируете данные и т. Д., Затем закрываете их; Считается, что такого рода функции выполняют несколько задач, что может быть плохо. Сначала есть причины производительности. Открытие и чтение из самого файла является, так сказать, дорогой вычислительной задачей. Вы также пытаетесь создавать объекты на лету, и это может быть плохо, если вы никогда не проверяли достоверность значений, полученных из файла. Посмотрите на мой код ниже, и вы увидите шаблон проектирования, на который я ссылаюсь, где каждая функция несет свою ответственность. Это также помогает предотвратить file corruption
.
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <fstream>
#include <exception>
struct MenuItem {
string menuItem;
double menuPrice;
int menuCount;
};
// This function is not used in this case but is a very helpful function
// for splitting a string into a vector of strings based on a common delimiter
// This is handy when parsing CSV files {Comma Separated Values}.
std::vector<std::string> splitString( const std::string& s, char delimiter ) {
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream( s );
while( std::getline( tokenStream, token, delimiter ) ) {
tokens.push_back( token );
}
return tokens;
}
void getDataFromFile( const char* filename, std::vector<std::string>& output ) {
std::ifstream file( filename );
if( !file ) {
std::stringstream stream;
stream << "failed to open file " << filename << '\n';
throw std::runtime_error( stream.str() );
}
std::string line;
while( std::getline( file, line ) ) {
if ( line.size() > 0 )
output.push_back( line );
}
file.close();
}
void parseFileData( const std::vector<std::string>& fileContents, std::vector<MenuItem> menuItems ) {
// The first param is the contents of the file where each line
// from the file is stored as a string and pushed into a vector.
// Here you need to parse this data. The second parameter is the
// vector of menu items that is being passed by reference.
// You can not modify the fileContents directly as it is const and read only
// however the menuItems is passed by reference only so you can update that
// This is where you will need to go through some kind of loop and get string
// of text that will stored in your MenuItem::menuItem variable.
// then the next string will have your price. Here you showed that your
// text file has `$` in front of the value. You will then have to strip this out
// leaving you with just the value itself.
// Then you can use `std::stod( stringValue ) to convert to value,
// then you can save that to MenuTiem::menuPrice variable.
// After you have the values you need then you can push back this temp MenuItem
// Into the vector of MenuItems that was passed in. This is one iteration of
// your loop. You continue this until you are done traversing through the fileContents vector.
// This function I'll leave for you to try and write.
}
int main() {
try {
std::vector<std::string> fileConents;
getDataFromFile( "test.txt", fileConents );
std::vector<MenuItem> data; // here is the menu list from your example
generateVectors( fileConents, data );
// test to see if info is correct
for( auto& d : data ) {
std::cout << data.menuItem << " " << data.menuPrice << '\n';
}
} catch( const std::runtime_error& e ) {
std::cerr << e.what() << '\n';
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Что касается вашей ошибки или сбоя, вы, вероятно, либо обращались к индексу, который находится за концом вектора, либо пытались использовать содержимое вектора, в котором были неверные данные.