Bezpieczne wydobycie danych z pliku CSV i zapisanie do tablicy

0

Witam ponownie :)
mam takie pytanie: przechowuję dużą liczbę danych w pliku CSV. Dane podzielone są od kilku do kilkudziesięciu zmiennych. Każda zmienna jest w innej kolumnie w pliku (zwykła tabela, gdzie kolumny to n-zmienna a wiersze to i-zestaw w próbie).
Obecnie napisałem taki kod do wydobycia tych danych:

double**zmienne = new double*[ilosc_danych];
for(i=0; i<ilosc_danych; i++)
	zmienne[i] = new double[ilosc_zmiennych];

string nazwa_pliku = "nazwa_pliku.csv";
ifstream out(nazwa_pliku.c_str());
if(!out)
	cout << "nie można otworzyć pliku" << endl;
else
	{
	i=0;
        char znak; //do wrzucania separatora
	while(out >> zmienne[i][0] >> znak >> zmienne[i][1] >> znak >> zmienne[i][2] >> znak >> zmienne[i][3] >> znak >> zmienne[i][4])
		{
		i++;
		}

lub alternatywna wersja dla większej liczby zmiennych:

while(out)
			{
			for(j=0; j<liczba_zmiennych-1;j++)
				out >> zmienne[i][j] >> znak;
			out >> zmienne[i][4];
			i++;
			}
}

Kod działa póki co prawidłowo!
Mam jednak pewne obawy, gdyż w pliku docelowo ma być przechowywane kilkaset tysięcy danych - typu double. Moje obawy dot. przede wszystkim konwersji stringu/char-ów tych liczb z pliku na typ double -> czy przy większej ilości zmiennych nie ma tu większego niebezpieczeństwa, że coś się skopie i program źle odczyta ciąg znaków z pliku i zapisze mi jakieś śmieci do tablicy lub w ogóle się rozłoży?
Co w ogóle powiecie o tym kodzie? Jak go oceniacie? czy można go jakoś usprawnić - głównie odnośnie bezpieczeństwa wydobywania danych -> by przez przypadek nie zapisać do tablicy jakiś śmieci, które wszystko mi popsują w dalszym działaniu programu...
Przykładowo, jak w pliku między liczbami dam dwa przecinki to program do tego miejsca mi ładnie kopiuje dane a później nic nie robi :( -> ale nie zamyka się tylko po prostu przestaje kopiować dane... Więc nie wiem nawet, że coś się kopło :/

Pozdrawiam i z góry dziękuję wszystkim za pomoc!

0

A po zakończeniu pętli porównać czy i==ilosc_danych ?

0
_13th_Dragon napisał(a):

A po zakończeniu pętli porównać czy i==ilosc_danych ?

Tak, właśnie też na to wczoraj wpadłem :) - już po umieszczeniu posta
A jeśli chodzi o wydobywanie danych to wszystko jest ok? Też byście tak zrobili? :P
Bo jeszcze rozważałem wydobycie całych wierszy z pliku i dzielenie ich na zmienne (poprzez znalezienie separatora lub znaku końca wiersza) -> ale nie wiem czy pomysł jest wart zachodu... Co wy na to?

0
for(;(out)&&(i<ilosc_danych);++i)
  {
   out >> zmienne[i][0];
   for(j=1; j<liczba_zmiennych;++j)
     {
      out >> znak >> zmienne[i][j];
      if(znak!=';') out.clear(ios::fail);
     }
   out >> ws; // #include <iomanip> dla tego ws
  }

To jest uniwersalne;
Na kocu sprawdzić czy out nie jest w stanie - "źle" czy out jest na końcu pliku czy i==ilosc_danych

0

ja takie dane wczytywałem w ten sposób:

vector<vector<double> > data;
ifstream file("nazwaPliku.cvs");
string line;
while(getline(file,line)) {
    istringstream lineS(line);
    vector<double> rowData;
    string cell;
    while(getline(rowData,cell, ";")) {
         istringstream cellData(cell);
         double value;
         if (cellData >> value) {
               rowData.push_back(value);
               if (!(cellData >> ws).eof())
                   cerr << "Problem in line " << (data.size()+1) << " in column: " << rowData.size() << " cell contains extra value: " << cell << endl;
         } else {
               rowData.push_back(DUMY_VALUE);
               cerr << "Problem in line " << (data.size()+1) << " in column: " << rowData.size() << " cell contains none numerical value: " << cell << endl;
         }
    }
    data.push_back(rowData);
}
0

Dzięki wielkie Panowie!
przetestuję również wasze opcje i porównam :)
pozdrawiam!

0

Panowie, mam jeszcze ogromną prośbę: czy możecie mi wyjaśnić na czym polega zasada działania tego zapisu: out >> ws;? Cokolwiek to jest bardzo mi pomogło :)
Wiem, że to usuwa białe znaki, ale nie wiem co to ma do rzeczy - tj. skąd wzięły się opisane niżej problemy :/.

Miałem mały problem bo w pliku na początku każdego wiersza miałem 10 danych niepotrzebnych i nieliczbowych a później były moje dane typu double -> więc chciałem usunąć pierwsze 10 znaków. Dlatego zrobiłem w zapisie coś takiego:

 
char text[10];
char znak;
double value[x][y];
while(file.good()) //skrócona wersja, bez obsługi błędów etc.
{
file.get(text,10); //z tym nic nie robię (tylko usuwam)
file >> znak >> value[i][0] >> znak >> value[i][1] /*...*/;
cout << value[i][0] << ... //spawdzenie
i++;
}

Niestety program nie działał prawidłowo -> gdy dochodził do końca linii to następnie wczytywał ostatnią zapisaną wartość - i albo tak w nieskończoność albo stopował po dwóch liniach.
Natomiast dodając powyższy zapis tj. file >> ws; program zaczął działać jak należy! Czy możecie mi wyjaśnić ten fenomen? Czemu tak się dzieje?
Dodam może tylko, że w tych 10 pierwszych znakach była tylko 1 spacja!

0

ws - zjada białe znaki. Jeżeli go nie masz to po odczytaniu ostatniego wiersza masz jeszcze w pliku przynajmniej enter z tego ostatniego wiersza, więc nadal file.good() zwraca prawdę. Dopiero po file.get(text,10); file.good() przyjmuje wartość false.

0
_13th_Dragon napisał(a):

ws - zjada białe znaki. Jeżeli go nie masz to po odczytaniu ostatniego wiersza masz jeszcze w pliku przynajmniej enter z tego ostatniego wiersza, więc nadal file.good() zwraca prawdę. Dopiero po file.get(text,10); file.good() przyjmuje wartość false.

dzięki za wyjaśnienie. Średnio to rozumiem, ale załóżmy, że tak musi już być :)

0

Ostatnie pytanie:
dlaczego jak zmieniłem separator w pliku z "," na ";" to program mi się rozłożył? tzn. przestał mi wczytywać dane do zmiennych tak jak poprzednio :(
Dodam, że jak zmienię "," na inny znak np. literę "x" to program działa prawidłowo - a ze średnikami w pliku nie...
Dodatkowo program się "sypie" gdy wstawi się średnik ";" zamiast jednego ze znaków w pierwszym ciągu, który jest przecież kopiowany do tablicy char więc nie powinien mieć żadnego wpływu na działanie reszty programu :(

dziękuję za pomoc!

0

właśnie doszedłem, że tak się dzieje tylko, gdy korzysta się z pliku CSV -> w pliku txt jest wszystko w porządku...
Czy ktoś się orientuje, dlaczego program ma problem z wydobyciem średnika ";" jako znaku z pliku csv? I jak to można ewentualnie obejść?
Nie mam koncepcji na ten problem tj. co jeśli dane będą przechowywane w pliku CSV i będą odseparowane średnikiem :(

0

Kolejne fakty:
gdy w excelu podzieliłem komórki, w których były przechowywane dane to zniknęły separatory (przecinki) a program odczytuje teraz znak (nową komórkę) jako średnik i nie robi już błędów...
Czyli wygląda na to, że w pliku CSV nie powinno się przechowywać danych w jednej komórce zawierających średnik - bo program ma problem z jego odczytaniem...

0
MarekR22 napisał(a):

ja takie dane wczytywałem w ten sposób:

vector<vector<double> > data;
ifstream file("nazwaPliku.cvs");
string line;
while(getline(file,line)) {
    istringstream lineS(line);
    vector<double> rowData;
    string cell;
    while(getline(rowData,cell, ";")) {
         istringstream cellData(cell);
         double value;
         if (cellData >> value) {
               rowData.push_back(value);
               if (!(cellData >> ws).eof())
                   cerr << "Problem in line " << (data.size()+1) << " in column: " << rowData.size() << " cell contains extra value: " << cell << endl;
         } else {
               rowData.push_back(DUMY_VALUE);
               cerr << "Problem in line " << (data.size()+1) << " in column: " << rowData.size() << " cell contains none numerical value: " << cell << endl;
         }
    }
    data.push_back(rowData);
}

Witam, chciałem przetestować powyższy kod, niestety kompilator krzyczy mi błąd w miejscu:

while(getline(rowData,cell, ";")) {

oraz

rowData.push_back(DUMY_VALUE);

Odnośnie pierwszego domyślam się, że podany jest zły pierwszy argument w funkcji getline (chyba powinien być lineS - ale pewności nie mam!) oraz powinno być ';' zamiast ";".
W drugim przypadku nie mam pojęcia czym jest DUMY_VALUE i google również pierwsze słyszy o tym.

W związku z powyższym uprzejmie proszę o potwierdzenie lub poprawienie moich przypuszczeń odnośnie pierwszej zagadki oraz odpowiedź czy vector ma jakąś stałą (czy co to może być) typu podobnego do DUMY_VALUE - domyślam się, że to ma być jakaś wartość domyślna...
Z góry serdecznie dziękuję!

1 użytkowników online, w tym zalogowanych: 0, gości: 1