Permalänk
Medlem

[c++] filhantering

Hej!
Jag har nu i flera dagar försökt få till en funktion som ska läsa från min fil som jag exporterat ut från exel till .txt och sedan skicka informationen till en array.
informationen i filen ser ut så här.

2040 //Livsmedelsnamn Energi (kcal)(kcal) Protein(g) Fett(g) Kolhydrater(g) Talg nöt 656 7 71 0 Späck gris 763 2,8 85 0 Ister gris 884 0 100 0 Kokosfett 884 0 100 0 Matfettsblandning havssaltat fett 80% berikad typ Bregott 712 0,5 80 0,5 Matfettsblandning fett 60% berikad typ Bregott mellan 543 1 60 2

mitt mål nu är att gör en funktion som läser filen, tar numret högst upp och sätter min forloop att snurra så länge, eftersom det är så många rader filen består av och så att min variabel nrOfElements får det värdet så jag kan göra forloops sen när jag tex ska visa innehållet i arrayen.
den andra raden livsmedel etc etc har jag bara tagit med så ni vet vad det handlar om, den ska jag inte ha i filen.
sen så ska den "getline" och skicka namnet, kcal, protein, fett o kolhydrater o skicka till min konstruktor.
Och allt som är en string ska skickas som en string och allt som är en int/double ska skickas som det för att jag ska kunna göra beräkningar senare. Det är så kallat "tab-delimited".

så här har jag gjort, men det funkar inte.

#include <fstream> #include <sstream> #include <iostream> using namespace std; int main() { string lm[2500]; ifstream ifs("livsmedel.txt"); int lines; string input; stringstream ss; getline(ifs, input); //cout<<input<<endl; ss<<input; ss>>lines; istringstream buffer(lines); //int antal; //buffer >> antal; for(int i=0; i<lines && !ifs.fail(); i++) { getline(ifs,input); int antal; int kcal; double protein; double fett; double kolhydrat; ss<<input; ss>>kcal>>protein>>fett>>kolhydrat; lm[i] =(kcal, protein,fett, kolhydrat); } for(int i=0;i<20;i++) { cout<<lm[i]; } return 0; }

Håller på o bli galen på denna så tacksam för all hjälp!

Permalänk
Hedersmedlem
Skrivet av Z3R0:

istringstream buffer(lines); int antal; buffer >> antal;

Vad är tanken här (och duger inte lines)?

Permalänk
Medlem

ja du...nu när jag kollar på det så ser jag ingen mening med det...så jag tar bort det...

Jag läser in det talet som är överst men sen så händer inget mer

Permalänk
Hedersmedlem
Skrivet av Z3R0:

Jag läser in det talet som är överst men sen så händer inget mer

Jodå. Förutsatt att man ändrar till

for(int i=0; i<lines && !ifs.fail(); i++)

börjar inläsningen. Något man borde hantera är kommentarer (input kommer i loopens första varv innehålla "//Livsmedelsnamn Energi (kcal)(kcal) Protein(g) Fett(g) Kolhydrater(g)", vilket sannolikt ställer till det för det stackars stringstream-objektet.

Man kommer nog dock stöta på problem även för normala rader. Då du skickar in även livsmedelsnamnet i ss bör du nog även läsa ut det, och när man är färdig är läge att anropa ss.clear() för att nollställa felflaggor och liknande.
Det här ser också misstänkt ut:

lm[i] =(kcal, protein,fett, kolhydrat);

men redan innan bör man också hantera att vissa livsmedelsnamn består av många ord.

Permalänk
Medlem

jo klart efter du påpekade det så ändrade jag i den första posten så det står lines i for loopen men inget händer. och dessutom så finns inte den där raden du nämner ens den har jag tagit med här så ni vet vad det är för skit i filen, i själva verket finns inte den raden.

Permalänk
Medlem

min tanke är att den ska på nåt sätt hämta allt fram till den stöter på en tab.
när den hämtat en hel rad så omvandlas det som behöver omvandlas från string till int osv osv, sen skickas det till arrayen när det är klart så körs forloopen igen och allt håller på så länge !=eof().

Skulle vara trevligt om någon kunde hjälpa mig men o implementera det.

Permalänk
Hedersmedlem

Då är det nog först och främst livsmedelsnamnen som ställer till besvär. Testa att lägga till

ss >> input >> input;

efter

ss<<input;

för att bli av med dem för de tre första raderna i filen.

Har du debugmöjligheter, för övrigt? Det är ofta rätt givande att se var det blir fel.

Permalänk
Medlem

varför bli av med de tre första raderna?

kodar i VS så möjligheten finns, men kunskaperna är ganska begränsade.

Permalänk
Hedersmedlem
Skrivet av Z3R0:

varför bli av med de tre första raderna?

kodar i VS så möjligheten finns, men kunskaperna är ganska begränsade.

Nej, alltså du skickar in till exempel:
"Talg nöt 656 7 71 0"
och börjar sedan utläsningen med att försöka läsa en int, vilket misslyckas då det första elementet är "Talg". Istället får man först läsa ut två textsträngar eller också (hellre) låta bli att skicka in livsmedelsnamnet (skippa alla tecken före det första '\t', till exempel).

Skrivet av Z3R0:

kodar i VS så möjligheten finns, men kunskaperna är ganska begränsade.

Man har mycket att vinna även med väldigt knappa kunskaper. Placera till exempel markören på en lämplig rad och tryck på F9 (eller klicka i marginalen till vänster om raden). En röd boll dyker upp och i framtiden kommer körningen göra paus där. Då kan man passa på att till exempel hålla muspekaren över variabler för att se vad de innehåller innan man trycker på F10 för att stega till nästa rad eller F5 för att fortsätta körningen.

Permalänk
Medlem

ok, menar du att jag bara ska skicka nummren till arrayen och inte livsmedelsnamnen?

Permalänk
Hedersmedlem
Skrivet av Z3R0:

ok, menar du att jag bara ska skicka nummren till arrayen och inte livsmedelsnamnen?

Det är nog enklast (om man tillåter vita tecken i dem).

Permalänk
Medlem

men det hel ablir meningslöst om jag inte har livsmedelsnamnen.
Så det är ett måste :-/

Permalänk
Hedersmedlem
Skrivet av Z3R0:

men det hel ablir meningslöst om jag inte har livsmedelsnamnen.
Så det är ett måste :-/

Jo, men du skulle som sagt kunna leta rätt på det första tabbtecknet, spara texten före som namnet och behandla texten efter ungefär som nu.

Permalänk
Medlem

ok, har du nåt tips på hur jag kan gå till väga för o fixa det, jag har verkligen försökt fixa detta i flera dagar nu och det går bara inte.
Har ingen aning hur jag ska göra kodmässigt.

Permalänk
Hedersmedlem

Såhär kanske?

int antal; int kcal; double protein; double fett; double kolhydrat; string namn; for(int i=0; i<lines && ifs.good(); i++) { getline(ifs,input); if(!input.size()) continue; ss.clear(); namn = input.substr(0, input.find('\t')); input = input.substr(namn.size() +1, input.size()-1-namn.size()); replace(input.begin(), input.end(), ',', '.'); ss<<input; ss>>kcal>>protein>>fett>>kolhydrat; //lm[i] =(kcal, protein,fett, kolhydrat); }

Vad vill man för övrigt göra med informationen när den väl är inläst? lm är ett fält av strängar, men det är lite mera komplicerat att göra en textsträng av blandade variabeltyper (och om det är det enda man vill är det kanske lämpligare att bara använda textsträngar från början).

Permalänk
Medlem

egentligen har jag en array med pekare dvs en Livsmedel**lm.
så om jag ska skicka det där till min array får jag kanske göra en forloop som sen skapar nytt minner och skickar med de sakerna.

kanske

for(int i=0;i<lines;i++) { this->lm[i]=new Livsmedel(name, kcal, kolhydrater, protein, fett); }

men ja informationen ska användas för till exempel göra beräkningar, så som att användaren kan söka fram ett livsmedel och sedan lägga in det i sin"kostdagbok" och mata in hur mkt han har konsumerat och då ska beräkningar för P,K,F göras.
så min tanke är att varje slot i min array ska innehålla ett livsmedel, då kan jag lätt hitta, ändra, ta bort osv osv

Permalänk
Hedersmedlem

lm[i]=new Livsmedel(name, kcal, kolhydrater, protein, fett);

Detta borde väl passa bra istället för den lm-tilldelning som sker nu?

Permalänk
Medlem

joo, det bör det göra.

Men det kodexemplet jag kom fram till skrev jag i en separat fil bara för att få till läsningen, och där har jag bara skapat en string array men det ska inte vara så egentligen.

Permalänk
Medlem

dessutom så klagar den på "replace". Identifier not found.

Permalänk
Hedersmedlem
Skrivet av Z3R0:

dessutom så klagar den på "replace". Identifier not found.

Ah, lägg till

#include <algorithm>

(eller radera raden och använd decimalpunkt istället för decimalkomma i livsmedelsfilen)

Permalänk
Medlem

så kodexemplet du skrev innan ska göra det jag vill att min funktion ska göra?

jag försöka göra en cout på allt i arrayen och då började datorn pipa som fan

Permalänk
Hedersmedlem
Skrivet av Z3R0:

så kodexemplet du skrev innan ska göra det jag vill att min funktion ska göra?

jag försöka göra en cout på allt i arrayen och då började datorn pipa som fan

Den borde klara inläsningen i alla fall; sedan får man som sagt lägga till något för att ta hand om informationen.

Permalänk
Medlem

när du säger ta hand om informationen vad menar du då?

Permalänk
Hedersmedlem
Skrivet av Z3R0:

när du säger ta hand om informationen vad menar du då?

Att skapa de där Livsmedel-objekten du nämnde tidigare till exempel.

Permalänk
Medlem

egentligen så är allt detta färdigt, detta med inläsning till array är det näst sista steget, så nu måste jag bara göra en main för att testa funktionen, sen måste jag också försöka lista ut hur man ska kunna skapa en funktion som spara till fil.

men jag ska försöka fixa detta med main sen återkommer jag om hur det funkar.

Tack för hjälpen!

Permalänk
Medlem

Tjena nu har jag implementerat en main och funktionen läser in från filen, men inte allt...
Jag får upp Namn: Unknown och det beror på att min default konstruktor säger att alla strängar ska sättas till unknown, dvs att namnet aldrig skickas till konstruktorn, vad kan det bero på?

Permalänk
Medlem

Du säger ju själv vad det beror på, du tilldelar alla instanser namnet unknown i defaultkonstruktorn, du får väll använda en setName(...) eller en andra konstruktor som tar namnet som inparameter och sedan tilldelar du det till objektet.

Hur ser det ut nu?

Permalänk
Medlem

ja men i samma defaultkonstruktor så säger jag att alla ints ska vara 0, dvs kcal=0, protein=0 osv osv, och de värdena ändras efter inläsningen av filendet är bara namnet som fortfarande är unknown

Permalänk
Hedersmedlem

Med till exempel denna klass:

class Livsmedel { public: Livsmedel(string name, int kcal, double kolhydrater, double protein, double fett) { this->name = name; this->kcal = kcal; this->kolhydrater = kolhydrater; this->protein = protein; this->fett = fett; } string name; int kcal; double kolhydrater, protein, fett; };

fungerar raden du hade tidigare:

lm[i]=new Livsmedel(namn, kcal, kolhydrat, protein, fett);

(förutsatt att lm är ett Livsmedel*-fält).

Permalänk
Medlem

detta är min konstruktor.

Livsmedel::Livsmedel(string name, int kcal, double protein, double carb, double lipid) { this->name=name; this->kcal=kcal; this->protein=protein; this->carb=carb; this->lipid=lipid; }

array.

Livsmedel ** lm;