Уже есть несколько хороших ответов и один, который уже был принят;Однако я хотел бы предложить свое решение не только в качестве правильного ответа на вашу проблему, но и в отношении хорошей практики проектирования.ИМХО, когда речь идет о считывании информации из файла и сохранении его содержимого в переменных или структурах данных, я предпочитаю делать это особым образом.Мне нравится разделять функциональность и ответственность определенных операций на их собственные функции:
- 1: Сначала я хотел бы иметь функцию для открытия файлапрочитайте содержимое и сохраните информацию в виде строки, потока или большого буфера.Как только из файла будет прочитано соответствующее количество информации, функция закроет дескриптор файла, как мы закончили, и затем вернет результаты.Есть несколько способов сделать это, но все они похожи.
- a: Считать одну строку из файла и вернуть обратно строку или поток.
- b: Считать всю информацию из формыфайл строка за строкой, сохраняйте каждую строку в своей собственной строке или потоке и возвращайте вектор этих строк или потоков.
- c: Считайте все содержимое файла водиночная строка, поток или большой буфер и возвращаем его обратно.
- 2: После того, как у меня будет содержимое этого файла, я обычно вызываю функцию, которая будет анализироватьэти данные и эти функции будут различаться в зависимости от типа контента, который необходимо проанализировать на основе структур данных, которые будут использоваться.Кроме того, эти функции синтаксического анализа вызовут функцию, которая разделит строку на вектор строк, называемый токенами.После вызова функции разделения строки при разборе данных будут использоваться строковые манипуляторы-преобразователи, чтобы преобразовать строку в требуемые встроенные типы, необходимые для текущей используемой структуры данных, и сохранить их в структуре данных, которая являетсяпередано по ссылке.
- 3: Существует две разновидности моей функции splitString.
- a: Один принимает один символ в качестве разделителя.
- b: Другой принимает строку в качестве разделителя.
- c: Обе функции будут возвращать вектор строк на основе используемого разделителя.
ВотПример моего кода, использующего этот текстовый файл для ввода.
time.txt
4:32:52
main.cpp
#include <vector>
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>
#include <exception>
struct Time {
int hours;
int minutes;
int seconds;
};
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;
}
std::string getLineFromFile( const char* filename ) {
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;
std::getline( file, line );
file.close();
return line;
}
void parseLine( const std::string& fileContents, Time& time ) {
std::vector<std::string> output = splitString( fileContents, ':' );
// This is where you would want to do your sanity check to make sure
// that the contents from the file are valid inputs before converting
// them to the appropriate types and storing them into your data structure.
time.hours = std::stoi( output.at( 0 ) );
time.minutes = std::stoi( output.at( 1 ) );
time.seconds = std::stoi( output.at( 2 ) );
}
int main() {
try {
Time t;
std::string line = getLineFromFile( "time.txt" );
parseLine( line, t );
std::cout << "Hours: " << t.hours << '\n'
<< "Minutes: " << t.minutes << '\n'
<< "Seconds: " << t.seconds << "\n\n";
} catch( std::runtime_error& e ) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
Вывод:
Hours: 4
Minutes: 32
Seconds: 52
Теперь, как вы можете видеть в данной конкретной ситуации, используемые здесь функции предназначены только для чтения одной строки из файла.и конечно самая первая строка из файла.У меня есть другие функции в моей библиотеке, не показанные здесь, которые будут читать каждую строку файла, пока не останется больше строк для чтения, или прочитать весь файл в один буфер.У меня есть другая версия разделенной строки, которая будет принимать строку в качестве разделителя вместо одного символа.Наконец, для функции синтаксического анализа каждая функция синтаксического анализа в конечном итоге будет уникальной, поскольку будет зависеть от структуры данных, которую вы пытаетесь использовать.
Это позволяет коду быть читаемым, так как каждая функция делает то, что должна, и ничего более.Я предпочитаю этот дизайн, а не факт получения информации из файла и анализа ее при открытом файле.Слишком много вещей может пойти не так, пока файл открыт, и если данные читаются неправильно или повреждены, но до такой степени, что компилятор не жалуется на это, тогда ваши переменные или структуры данных могут содержать недопустимую информацию без вашего ведома.,По крайней мере, таким образом вы можете открыть файл, получить из него то, что вам нужно, и сохранить его в виде строки или вектора строк, закрыть файл, когда закончите чтение, и вернуть обратно содержимое.Затем функция синтаксического анализа несет ответственность за проверку данных после их токенизации.Теперь, в текущей функции синтаксического анализа, которую я показал выше, я не делал никаких проверок работоспособности, чтобы упростить задачу, но именно здесь вы должны проверить свои данные, чтобы убедиться, что информация верна, прежде чем вернуть обратно заполненную структуру данных.
Если вас интересует другая версия, в которой из файла читается несколько строк, просто прокомментируйте запрос, и я добавлю его к этому ответу.