У меня есть файл с именем 1.txt, он содержит 3 строки, каждая строка хранится в объекте класса entry
следующим образом:
1* 10/12/2020 5:30 a 11:15 p 0 0 0 0 -----
2* 11/12/2020 3:45 a 5:46 a 0 0 0 0 -----
3* 12/12/2020 5:46 a 4:56 p 34.6 0 0 0 blah
и я читаю из этого файла построчно в Entry e
и сохраняю каждую запись в std::vector<Enrty>records
следующим образом:
void read_records(std::ifstream file, Entry e, std::vector<Entry>&records)
{
std::string line;
std::cout << "READING TEXT FILE CONTENTS..." << std::endl;
while (file)
{
getline(file, line);
e.read_text(tokenize(line)); // tokenize tokenizes line to tokens and e.read_text stores data from that line into e
records.push_back(e);
e.reset(); // this resets e back to original state
}
}
когда я отображаю records
после вызова этой функции, это дает мне дополнительную запись в таких записях, как так,
Содержимое std::<Entry>records
:
1* 10/12/2020 5:30 a 11:15 p 0 0 0 0 -----
2* 11/12/2020 3:45 a 5:46 a 0 0 0 0 -----
3* 12/12/2020 5:46 a 4:56 p 34.6 0 0 0 blah
3* 12/12/2020 5:46 a 4:56 p 34.6 0 0 0 blah // I'm getting this extra entry in records when the file only contains 3 entries.
Пожалуйста, объясните, почему это происходит, и теперь, чтобы исправить это в Visual Studio C++.
@ Кевин, это, кажется, проясняет это, я думаю, это может быть проблема, но как это исправить?
@PratapBiswakarma, как в ответе Аюши, замените while(file)
на while(getline(file, line))
Теперь это имеет смысл. А также спасибо за отличную ссылку @Kevin
Я думаю, что проблема здесь может заключаться в утверждении while
-
это добавит дополнительную итерацию к тому, что вы ожидаете, потому что это условие становится ложным только после того, как вы прошли конец файла.
while(file) {
// ...
}
getline
считывает всю строку за раз, и, поскольку EOF не является строкой, вы избегаете нежелательной дополнительной итерации.
Это правильный способ приема файлового потока в этом случае использования:
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <vector>
int main() {
std::vector<std::string> records;
std::ifstream infile("thefile.txt");
std::string line;
while (std::getline(infile, line)) {
records.push_back(line);
}
for (std::string e : records) {
std::cout << e << std::endl;
}
}
Кажется, это решило проблему, но можно ли подробнее? Например, почему while (std::getline(infile, line))
лучше, чем while(file)
? Разве while (std::getline(infile, line))
не должно работать так же, как while(file)
?
@PratapBiswakarma - разница в том, что с while (file)
, когда вызов getline
терпит неудачу из-за достижения конца ввода, код в остальной части тела цикла выполняется; только после этого выполняется тест в while (file)
. Проверяя результат вызова getline
, когда ввод заканчивается, код немедленно выходит из цикла.
@PeteBecker Понятно! Спасибо! Можете ли вы объяснить, как этот метод будет, если я читаю записи из двоичного файла?
Я имею в виду двоичный файл, в котором мы просто пишем двоичные данные и не используем форматирование, такое как пробел или новая строка и т. д.
while (file)
по-прежнему верно, потому что файл находится в хорошем состоянии до тех пор, пока он не прочитает eof