Чтение одной целой ячейки csv-файла в переменную

#c #list #csv #file

#c #Список #csv #файл

Вопрос:

В CSV-файле на строку приходится по три ячейки. Я пытаюсь прочитать каждую ячейку в закрытую переменную-член класса, который я создал. Я не могу понять, как прочитать всю ячейку A1 в одну строковую переменную, затем B1 в двойную переменную и C3 в другую отдельную двойную переменную. Я поиграл с getline и перегрузкой ostream operator >> но безрезультатно.

 class LinkedTemp
{
private: 
// the struct that will temporarily hold all items being read from file
struct Govee
{
string date;
double temperature;
double humidity;
struct Govee *next;
};

Govee *head; // pointer to head of all ListNodes

string time;
double temp;
double humi;

public:
// default constructor 
// set private members 
LinkedTemp()
{
head = nullptr;

time = "";
temp = 0.0;
humi = 0.0;

}

void append()
{
Govee *nodePtr, *newNode = nullptr;

// create a newNode and fill it with data (node will then be appended)
newNode = new Govee;
newNode->date = this->time;
newNode->temperature = this->temp;
newNode->humidity = this->humi;
newNode->next = nullptr;    

// start at beginning of list
nodePtr = head;

// if list does not exist, make node the first node
if (!head)
head = newNode;


else
{
// traverse the list
while (nodePtr != nullptr)
    nodePtr = nodePtr->next;

// append newNode onto the end of the list
nodePtr->next = newNode;
}//end else statement

}//end append function


// supports 
// cout << object
friend ostream amp;operator << (ostream amp;strm, LinkedTemp amp;r)
{
strm << "Date: " << r.time << endl;
strm << "Temp: " << r.temp << endl;
strm << "Humi: " << r.humi << endl;
return strm;
}

// will fill all public member variables of class 
// file >> object
friend istream amp;operator >> (istream amp;strm, LinkedTemp amp;r)
{   
getline(strm, r.time);
strm >> r.temp;
strm >> r.humi;
return strm;
}

}; // end class 
 

И в основном у меня есть что-то вроде:

 int main()
{

//open file
fstream file;
file.open("Feb.csv");

// create LinkedTemp object
LinkedTemp list;

// read file into LinkedTemp object
// while (file)
//{
file >> list;
//}
// append the information into the list
// list.append();

// display all the contents of the list
cout << list;

return 0;
}
 

Но я либо читаю всю строку, либо только часть 2020-02-07 файла .csv, а не всю 2020-02-07 00:00:00. Формат файла .csv см. в прикрепленном изображении. Изображение файла .csv

Комментарии:

1. Сначала показанный код вызывает getline . Это считывает всю строку в time . Все три значения. Затем показанный код снова использует >> оператор во входном потоке. Имеет ли это смысл для вас? Итак, первая строка в csv-файле находится в строке. Это становится «временем». Вместо этого код использует >> для чтения все, что следует за первой строкой, как слова, разделенные пробелами , в файле csv. Общий итог: первая прочитанная строка становится строкой. >> считывает два слова после первой строки, которые должны быть разделены пробелами. Остальная часть файла игнорируется. Как сказал бы мистер Спок: это крайне нелогично.

2. Не могли бы вы сделать отступ в своем коде? Трудно читать все в столбце 1.

3. @John Kugelman — спасибо!

Ответ №1:

Вы можете сделать это , сохранив все токены в vector of vector of strings . Это создаст 2-мерную строковую матрицу, которую вы можете обработать в любом случае, когда захотите позже. Следующий код — это то, что вам нужно:

 #include <string>
#include <fstream>
#include <sstream>
#include <iostream>

struct data{
    std::string s0;
    double d0;
    double d1;
};

int main()
{
    // create a vector of your class to store all of your data, 
    // in your case it's a list so you can tweak it according to your needs
    std::vector <data> vec_data;
    // create a vector of vectors of strings to store all the tokens you read from file
    std::vector <std::vector<std::string>> vec_tokens;

    std::ifstream is("file.csv");
    if(is.is_open()) {
        std::string line;
        while(getline(is, line)) {
            std::stringstream ss_line(line);
            std::string token;
            std::vector <std::string> vec_temp;
            while(getline(ss_line, token, ',')) {
                vec_temp.push_back(token);
            }
            vec_tokens.push_back(vec_temp);
        }
    }

    // convert all tokens into data
    for(auto i: vec_tokens) {
        vec_data.push_back({i[0], std::stod(i[1]), std::stod(i[2])});   
    }

    // clean up tokens
    vec_tokens.clear();

    // check if it worked
    for(auto i: vec_data) {
        std::cout << i.s0 << " , " << i.d0 << " , " <<  i.d1    << std::endl;
    }


    return 0;
}
 

Возможно, вам потребуется обработать исключения (например, для std::stod ) в случае, если программе предоставлен мусорный CSV-файл.