[C++] Edycja danych w pliku


(Begi89) #1

Nie wiem dla czego coś takiego mi nie działa

std::fstream plik;

	std::string dane;

    plik.open( "test.ini", std::ios::out );


	if( plik.good() == true )

	{

       //tu operacje na pliku

		getline( plik, dane ); //wczytanie CAŁEGO jednego wiersza danych

		getline( plik, dane );

		getline( plik, dane );

		getline( plik, dane );

		getline( plik, dane );

		getline( plik, dane );

		getline( plik, dane );

		getline( plik, dane );


		plik << mnoznik;

		plik.flush();

		plik.close();

	}

mnoznik jest typu double

W programie chodzi o to, żeby na bieżąco zmieniać 8 linijkę (która zawiera liczbę) w pliku ini

pomocy


([alex]) #2

Bo otworzyłeś plik do zapisu.

użyj ifstream lub std::ios::in


(Wojtekbogocki) #3

Siemka, powiem ci gdzie masz błąd (mogę się mylić bo kod analizowałem w pamięci), a ty go rozwiążesz, nie zrobię nic za ciebie, jak chcesz się nauczyć programować to najpierw naucz się sam sobie radzić :stuck_out_tongue:

Ok przejdźmy do rzeczy:

Mówisz o rzeczywistym pliku *.ini czy o pliku, któremu nadałeś to rozszerzenie? Zakładam, że to drugie (jeśli nie to nie męcz się z tym i zajrzyj do dokumentacji WinAPI albo znajdź w necie jakąś bibliotekę do obsługi takich plików); program nie działa (a raczej działa błędnie) bo czytasz getline'em osiem linijek a następnie tam gdzie funkcja skończyła czytanie dopisujesz liczbę, potem znowu to robisz, tym razem za ostatnio dopisaną, i znowu, w efekcie gdy mnożnik to kolejno 0.503d, 23.0d, 398.9932d, ósma linijka wygląda tak:

0.50323.0398.9932

Oczywiście zakładam, że ta ósma linijka istnieje w tym pliku i nigdzie wcześniej nie ma !EOF.

Ok, to wyjaśniłem na czym polega problem, więc teraz twoja kolej żeby go rozwiązać :stuck_out_tongue:

PS.

Zamiast kombinować z getline(), przesuń po prostu wewnętrzny kursor pliku do ósmej linijki (poszukaj w dokumentacji jak to się robi), zwiększysz wydajność i z kilku linijek zrobisz jedną.


(Begi89) #4
  1. jest to rzeczywisty plik ini

  2. 0.50323.0398.9932 <- nic takiego się nie robi.... plik zostaje bez zmian w oryginalnej niezmienionej postaci


(Drobok) #5

Może plik jest chroniony przez zapisem, spróbuj cokolwiek do niego dopisać. Co do kodu się nie wypowiem ponieważ twoje podejście jest mało dla mnie zrozumiałe ;]


(Sawyer47) #6

Niejako dołączam się do pytania, bo próbowałem dojść i nie wiem czemu to nie działa. Czy ktoś znający lepiej iostream i fstream mógłby się wypowiedzieć? Żeby było zabawniej, poniższy kod nie pisze do pliku, chyba, że doda się tellp lub tellg przed wywołaniem operator<<:

#include 

#include 

#include 


int main()

{

	std::fstream plik;

	std::string dane;

	plik.open("test.ini");


	if(plik.good())

	{

		for(int i = 0; i < 7; ++i)

			getline( plik, dane ); //wczytanie CAŁEGO jednego wiersza danych


// plik.tellp(); // ?

		plik << 'A';

		plik.flush();

		plik.close();

	}

	return 0;

}

W celach testowych stworzyłem sobie po prostu plik który w w N-tej linii ma cyfrę N. Gdy odczyta się pozycje w pliku przez tellp/tellg odpis się odbywa. Czy któryś z bardziej doświadczonych kolegów mógłby to skomentować?

Kompiluję g++ 4.5.2, bez żadnych dodatkowych flag.


(Wojtekbogocki) #7

Skoro to rzeczywisty plik *.ini to: http://darkcult.nazwa.pl/wiki/index.php/Pliki_INI, masz tu ładnie, po polsku wytłumaczone co i jak przy użyciu Windows API :slight_smile:


([alex]) #8

plik.open("test.ini",ios::in|ios::out);


(Begi89) #9

Jednak, to jest zwykły plik txt zapisany jako .ini.

wygląda mniej więcej tak

10 robi costam costam

2 odpowiada za to i za to

0.4 ustawia to i to

#include 

#include 

#include 


int main()

{

   std::fstream plik;

   std::string dane;

   plik.open("test.ini", std::ios::in|std::ios::out);


   if(plik.good())

   {

      for(int i = 0; i < 7; ++i)

      getline( plik, dane ); //wczytanie CAŁEGO jednego wiersza danych

  // plik.tellp(); // ?

      plik << 'A';

      plik.flush();

      plik.close();

   }

   return 0;

}

podmieniłem ten kod od Sawyera i to dalej nic nie robi


(Drobok) #10

Jestem zielony z waszej metody, oraz ogólnie z plików. Ale takie coś działa:

#include 

#include 

#include 

#include 

using namespace std;

int main()

{

   fstream plik("test.ini");

   ofstream plik2("t.ini");

   string dane;

   if(plik)

   {

	   int i=0;

		while(getline( plik, dane ))

		{

			i++;

			if(i==8)

				plik2 << "zmieniamy" << endl;

			else

				plik2 << dane << endl;

		}

		plik2.close();

		plik.close();

		remove("test.ini");

		rename("t.ini","test.ini");

   }

   return 0;

}

([alex]) #11
std::fstream plik;

   std::string dane;

   plik.open("test.ini", std::ios::in|std::ios::out);


   if(plik.good())

   {

      for(int i = 1; i < 7; ++i) getline( plik, dane ); // pomijamy 7 wierszy

      plik << 'A';

      plik.close();

   }

drobok, nie rozumiem czemu zawsze musisz tak strasznie skomplikować tak proste rzeczy?


(Drobok) #12

Owszem lubię komplikować życie bez komplikacji byłoby nudne ;], ale twoim sposobem, dodając tylko nagłówkowe, int main i returna. Nadal niestety nie działa (tzn po skompilowaniu w pliku test.ini nie ma żadnego A). Może to brak jakiejś biblioteki w kompilatorze. Natomiast mój bardzo komplikujący tak prostą rzecz i ciężkawy program to a w 8 linijce dodaje. Ten kod również wydaje się dobry, jednak coś z nim nie tak, podobnie myślał Sawyer, ty pomijasz flush, jednak sam przyzwał że nie działa i nie wie dlaczego ;]


(Wojtekbogocki) #13

Bo żeby coś wpisać w tej ósmej linijce to musisz ją najpierw mieć, pokopaj w enter w tym pliku tak żeby zrobić tą ósmą linijkę i wtedy odpal kod [alex]-a.


(Drobok) #14

Testuję na pliku:

1

2

3

4

5

6

7

8

Nie dopisuje nic ;]

//edit entery też próbowałem i nie działa ;]


(Wojtekbogocki) #15

A niech cię, naprawdę masz jakiś dziwny problem, poczekaj zaraz napiszę coś w VC i wstawię 100% działający kod.


(Sawyer47) #16

@drobok a jakim kompilatorem kompilowałeś?

Popróbowałem na innych wersjach g++, 4.4 i 4.5 dają to dziwne zachowanie, natomiast na 4.6 działa zgodnie z przewidywaniami, wygląda to na dziwny bug g++.


(Drobok) #17

Ms Visual C++ Express ;]


(Wojtekbogocki) #18

Rozwiązałem problem, dla zapisu plików używa się klasy ofstream a dla ich odczytu ifstream - osobliwość VC++.

Oo działający kod:

#include 


using namespace std;


bool addNum(const char cFile[], int nNumber)

{

	char cTemp[] = "temp.tmp";

	ifstream ifstrFile;

	ofstream ofstrFile;

	ifstrFile.open(cFile, ios::in);

	ofstrFile.open(cFile, ios::out | ios::app);


	if(ifstrFile.good() && ofstrFile.good())

	{

		char cBuff[256] = "";


		for(int i = 0; i < 8; ++i)

		{

			ifstrFile.getline(cBuff, 256);

		}

		ofstrFile << nNumber;

		return true;

	}

	else

		return false;

}


int main(int argc, char **argv)

{

	addNum("file.ini", 2);

	return 0;

}

Dołącza podaną mu cyfrę na koniec ósmej linijki :slight_smile:


(Drobok) #19

Podmienić / nie dopisać ;]

Na necie wszystkie takie pytania sprowadzają się do przepisania pliku do innego, a potem do ich podmiany. Ew do zapisu w momencie danej, ale to traci pozostałą jego część ;/


(Wojtekbogocki) #20

Aj tam ważne, że ogarnąłem strumienie plikowe :stuck_out_tongue: Teraz taka podmiana to buła z masłem i nutellą ;]