Чтение файла CSV с обнаружением последнего поля в файле - PullRequest
0 голосов
/ 25 сентября 2018

Я пытаюсь прочитать файл CSV, и у меня есть три поля, которые я должен прочитать, и самое последнее поле является целым числом, и я вылетал в последней строке файла с функцией стои, так как естьнет символа новой строки, и я не уверен, как определить, когда я в последней строке.Первые два оператора getline читают первые два поля, и мой третий getline читает и ожидает целое число, и мой разделитель для этого только '\ n', но это не будет работать для самой последней строки ввода, и мне было интересноЕсть ли обходной путь для этого?

Мои типы полей, которые я ожидаю, это [int, string, int], и я должен включить пробелы в среднее поле, поэтому я не думаю, что использование stringstream для этого будет эффективным

while (! movieReader.eof() ) { // while we haven't readched end of file
    stringstream ss;
    getline(movieReader, buffer, ','); // get movie id and convert it to integer
    ss << buffer; // converting id from string to integer
    ss >> movieid;
    getline(movieReader, movieName, ','); // get movie name
    getline(movieReader, buffer, '\n');
    pubYear = stoi(buffer); // buffer will be an integer, the publish year
    auto it = analyze.getMovies().emplace(movieid, Movie(movieid, movieName, pubYear ) );
    countMovies++;
}

1 Ответ

0 голосов
/ 25 сентября 2018

Для чтения и записи объектов можно было бы перегрузить операторы извлечения и вставки потока:

Пример csv:

1, The Godfather, 1972
2, The Shawshank Redemption, 1994
3, Schindler's List, 1993
4, Raging Bull, 1980
5, Citizen Kane, 1941

Код:

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <iterator>

void skip_to(std::istream &is, char delim) // helper function to skip the rest of a line
{

    char ch;
    while ((ch = is.get()) && is && ch != delim);
}

std::istream& eat_whitespace(std::istream &is) // stream manipulator that eats up whitespace
{
    char ch;
    while ((ch = is.peek()) && is && std::isspace(static_cast<int>(ch)))
        is.get();
    return is;
}

class Movie
{
    int movieid;
    std::string movieName;
    int pubYear;

    friend std::istream& operator>>(std::istream &is, Movie &movie)
    {
        Movie temp;  // use a temporary to not mess up movie with a half-
        char ch;     // extracted dataset if we fail to extract some field.

        if (!(is >> temp.movieid))  // try to extract the movieid
            return is;

        if (!(is >> std::skipws >> ch) || ch != ',') { // read the next non white char
            is.setf(std::ios::failbit);                // and check its a comma
            return is;
        }

        is >> eat_whitespace; // skip all whitespace before the movieName
        if (!std::getline(is, temp.movieName, ',')) {  // read the movieName up to the
            return is;                                 // next comma
        }

        if (!(is >> temp.pubYear))                     // extract the pubYear
            return is;

        skip_to(is, '\n');  // skip the rest of the line (or till eof())
        is.clear();

        movie = temp;  // all went well, assign the temporary
        return is;
    }

    friend std::ostream& operator<<(std::ostream &os, Movie const &movie)
    {
        os << "Nr. " << movie.movieid << ": \"" << movie.movieName << "\" (" << movie.pubYear << ')';
        return os;
    }
};

int main()
{
    char const * movies_file_name{ "foo.txt" };
    std::ifstream is{ movies_file_name };

    if (!is.is_open()) {
        std::cerr << "Couldn't open \"" << movies_file_name << "\"!\n\n";
        return EXIT_FAILURE;
    }

    std::vector<Movie> movies{ std::istream_iterator<Movie>{is},
                               std::istream_iterator<Movie>{} };

    for (auto const & m : movies)
        std::cout << m << '\n';
}

Вывод:

Nr. 1: "The Godfather" (1972)
Nr. 2: "The Shawshank Redemption" (1994)
Nr. 3: "Schindler's List" (1993)
Nr. 4: "Raging Bull" (1980)
Nr. 5: "Citizen Kane" (1941)
...