Zapis/odczyt struktury do/z pliku binarnego

Zapis/odczyt struktury do/z pliku binarnego
TM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:11
0

Cześć, mam problem z zapisem struktury do pliku binarnego.

Stworzyłem sobie taki kod:

Kopiuj
int myL = 1;

struct pData
{
	int currentL;
};

pData myData;

// -- Odczyt -- //
// .. otwarcie pliku juz po drodze
file.read((char*)&myData, sizeof(pData));

myData.currentL = myL; // To jest dobrze?

// -- Zapis -- //
file.write((char*)&myData, sizeof(pData));

Problem w tym, że to w ogóle nie działa, ale dlaczego? Kierowałem się poradnikami i jest tak samo, ale nie działa.

Endrju
Ale co to znaczy nie działa? Co chcesz osiągnąć? Co konkretnie jest nie tak?
TM
Do pliku zapisują się kompletne bzdury, a przy innych wartościach (np. 2) nie zapisuje się nic.
Endrju
Otwórz plik hexedytorem.
TM
Jak zrobię tak: int myL = 1; file.read((char)&myL, sizeof(myL)); itd. to jest już w porządku, w czym rzecz?
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Zapisuj poszczególne pola struktury.

Kopiuj
#include<iostream>
#include<fstream>
using namespace std;

struct test {
	int integer;
	float floating;
};

void save(const char* path, const test& source) {
	fstream file(path, ios::out | ios::binary);
	if (file.is_open()) {
		file.write((char*)&source.integer, sizeof(source.integer));
		file.write((char*)&source.floating, sizeof(source.floating));
		file.close();
	}
}

void load(const char* path, test& destination) {
	fstream file(path, ios::in | ios::binary);
	if (file.is_open()) {
		file.read((char*)&destination.integer, sizeof(destination.integer));
		file.read((char*)&destination.floating, sizeof(destination.floating));
		file.close();
	}
}

int main() {
	test testData;
	testData.integer = 12;
	testData.floating = 1.4f;
	save("test.bin", testData);

	test loaded;
	load("test.bin", loaded);
	cout << "Int: " << loaded.integer << " Float: " << loaded.floating << endl;	
	return 0;
}
edytowany 1x, ostatnio: grzesiek51114
grzesiek51114
grzesiek51114
@Endrju Oj no wiem, że tak też działa http://pastebin.com/vYf1ascZ
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
0
TurboMen napisał(a):

Problem w tym, że to w ogóle nie działa, ale dlaczego? Kierowałem się poradnikami i jest tak samo, ale nie działa.
Z tego co opisałeś w komentarzach to dobrze ci to działa. Przy zapisie binarnym który stosujesz, plik nie jest czytelny dla zwykłego użytkownika.
Weź napisz coś w wordzie po czym zapisz plik i spróbuj otworzyć ten plik notatnikiem, to jest właśnie zapis binarny.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
TM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:11
0

Powyższy kod daje taki sam rezultat jak mój.

Oprócz tego problemu, mam jeszcze pytanie dot. tego samego kodu: Jak sprawdzać dane w strukturze w warunku (np. if)?
Wystarczy: if(pData.currentL == myL) pData.currentL = 0;?

@_13th_Dragon: O to mi chodzi, plik ma się stać nieczytelny, a jednocześnie kod sobie odtworzy stamtąd dane - plik z zapisem danych gry :P

@grzesiek51114, mój kod jest aktualnie taki:

Kopiuj
struct s_pData
{
	int currentL;
};

s_pData pData;

void loadSettings()
{
	// -- First from file -- //
	ifstream file("game.dat", ios::binary);

	if (file.good())
	{
		// -- Language -- //
		file.read((char*)&pData.currentL, sizeof(pData.currentL));

		file.close();
	}
}

void saveSettings()
{
	ofstream file("game.dat", ios::binary);

	if (file.good())
	{
		// -- Language -- //
		file.write((char*)&pData.currentL, sizeof(pData.currentL));

		file.close();
	}
}

Dane zmieniam tak:

Kopiuj
pData.currentL = 1;
pData.currentL = 5;

itd..

edytowany 4x, ostatnio: TurboMen
Endrju
Już dwa razy Ci napisaliśmy, że tak ma być! Otwórz to czymś takim: https://en.wikipedia.org/wiki/Hex_editor
TM
Mi nie chodzi o otwieranie pliku przez użytkownika. Chodzi mi o to, że kod jest zepsuty i zapisuje dane tak, że potem nie może ich sam odczytać. Mi chodzi o to, że np. mam sobie daną ilość pieniędzy (pData.Money, np. 100$). Taką daną chce zapisać binarnie do pliku, a następnie chcę, żeby sobie kod to odczytał i wczytał do zmiennych.
grzesiek51114
grzesiek51114
A wygląda to może tak? http://pastebin.com/vYf1ascZ Bo ten kod działa. Może źle plik otwierasz. Może pokaż całość zarządzania zapisem i odczytem.
TM
Edytowałem post, zobacz.
stryku
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:607
0

Pokaż cały kod, który spłodziłeś. Cały. Razem z mainem itp.

Tak na marginesie to jeżeli z obiektem std::fstream nie robisz nic więcej to nie musisz go zamykać (file.close();) bo jest on napisany zgodnie z zasadami RAII (https://pl.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization). Czyli w skrócie - std::fstream sam zadba, żeby przy niszczeniu obiektu plik został zamknięty.

edytowany 2x, ostatnio: stryku
TM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:11
0
Kopiuj
struct s_pData
{
    int currentL;
};
 
s_pData pData;
 
void loadSettings()
{
    // -- First from file -- //
    ifstream file("game.dat", ios::binary);
 
    if (file.good())
    {
        // -- Language -- //
        file.read((char*)&pData.currentL, sizeof(pData.currentL));
        // Poprzednia wersja: file.read((char*)&pData, sizeof(pData));
 
        file.close();
    }
}
 
void saveSettings()
{
    ofstream file("game.dat", ios::binary);
 
    if (file.good())
    {
        // -- Language -- //
        file.write((char*)&pData.currentL, sizeof(pData.currentL));
        // Poprzednia wersja: file.write((char*)&pData, sizeof(pData));
 
        file.close();
    }
}

int main()
{
    loadSettings();

    pData.currentL = 2;

    saveSettings();

     return 0;
}
edytowany 1x, ostatnio: TurboMen
stryku
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:607
0

Ok, a teraz wyjaśnij jakiego oczekiwałeś rezultatu, a jaki otrzymałeś? Możesz też załączyć ten plik binarny.

edytowany 1x, ostatnio: stryku
TM
Chcę, aby do pliku zapisały się dane, których zwykły użytkownik po wejściu nie będzie w stanie odczytać, a kod po ponownym załadowaniu będzie w stanie odczytać i przypisać do zmiennej. Jak wspominałem, będę zapisywać wiele danych. Teraz jest aktualny język gry (1 - PL, 2 - ENG). Przy 1 zapisuje taki jakiś prostokąt pusty w środku, przy 2 nic nie zapisuje, przez co po ponownym uruchomieniu programu jest problem.
Endrju
Ostatni raz napiszę: UŻYJ HEKSEDYTORA.
stryku
wiadomości dotyczące wątku pisz w normalnych postach (:
TM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:11
0

Gdy zrobiłem taki kod:

Kopiuj
int *myL = 1;

file.write((char*)&myL, sizeof(myL));

...

file.read((char*)&myL, sizeof(myL));

To wszystko jest w porządku, kod poprawnie odczytuje zapisane dane.

Endrju
Ten kod jest całkowicie niepoprawny.
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Przecież to działa:

Kopiuj
int main()
{
	loadSettings();
	cout << pData.currentL << endl;
	pData.currentL = 88;
	saveSettings();
	return 0;
}

Program ładnie wczytuje wartość zapisaną podczas poprzedniego uruchomienia aplikacji. http://pastebin.com/HreKDcDT

PS: Zapisanie binarnie danych do pliku wcale nie oznacza, że użytkownik nie będzie mógł ich modyfikować vide hexa edytor.

edytowany 1x, ostatnio: grzesiek51114
TM
To teraz za 88 podstaw 1 albo 2.
grzesiek51114
grzesiek51114
No i czego oczekujesz? System zawsze odczyta zapisaną podczas poprzeniej sesji wartość. Dlatego przy zmianie wartości obiekru pData.currentL nie będziesz widział zmiany za pierwszym razem. Wszystko działa prawidłowo przecież.
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
1

Wystarczy tyle:

Kopiuj
#include <fstream>
#include <iostream>
using namespace std;

struct
  {
   int currentL;
   double cos;
  }
  pData = 
  {  
   0, // domyślna wartość dla currentL
   666.13, // domyślna wartość dla cos
  };
 
void loadSettings()
  {
   ifstream file("game.dat",ios::binary);
   file.read((char*)&pData,sizeof(pData));
  }
 
void saveSettings()
  {
   ofstream file("game.dat",ios::binary);
   file.write((char*)&pData,sizeof(pData));
  }

int main()
  {
   cout<<pData.currentL<<' '<<pData.cos<<endl; // musi być domyślne 0 666.13
   loadSettings();
   cout<<pData.currentL<<' '<<pData.cos<<endl; // muszą być ostatnie wartości
   pData.currentL+=2;
   pData.cos*=2;
   cout<<pData.currentL<<' '<<pData.cos<<endl; // te nowe, zmienione dane
   saveSettings(); 
   return 0;
  }

zauważ że jednym ciurkiem zapisujesz wszystkie wartości na raz.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
stryku
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad rok
  • Postów:607
1

A zakład o piątaka, że wszystko działa tak jak chcesz? (:

Kopiuj
int main()
{
	
	//ustawienie pl
    pData.currentL = 1;
 
 	//zapisanie danych do pliku
    saveSettings();
    
    //to, żeby bylo widac roznice
    pData.currentL = 2;
    
    std::cout<<pData.currentL<<endl;
    
    loadSettings();
 
    std::cout<<pData.currentL<<endl;
 
     return 0;
}

Zrób takiego maina i zobacz na wyniki

grzesiek51114
grzesiek51114
Wszystko działa tylko autor trochę nie rozumie dlaczego moim zdaniem.
stryku
No ja wiem, ale jak @Endrju nie może się doprosić, żeby otworzył hex edytor, to może przykład mu coś wyjaśni
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Zamień sobie save z load i przekonaj się, że wszystko naprawdę jest ok.

Kopiuj
int main()
{
	pData.currentL = 15;
	saveSettings();
	loadSettings();
	cout << pData.currentL << endl;
	return 0;
}

Przecież nie zobaczysz zmian w programie jeżeli najpierw odczytujesz wartości, a później je zapisujesz i zamykasz aplikacje. Jak chcesz zobaczyć zmienione zapisane dane kiedy zaraz po zapisie zamykasz program. Dopiero podczas drugiego uruchomienia będziesz to widział.

edytowany 1x, ostatnio: grzesiek51114
_13th_Dragon
@grzesiek51114, a teraz zakomentuj te save i load ... o nadał tak samo dobrze działa !! ;P
grzesiek51114
grzesiek51114
@_13th_Dragon jest tu jakiś cwaniak? :D
TM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:11
0

No nie działa, żadne z waszych rozwiązań.

Plik wyjściowy ma zawartość (dla 1): http://scr.hu/5icj/vhldo

WTF?

grzesiek51114
grzesiek51114
Weź edytor heksadecymalny i przekonasz się, że działa.
TM
To czemu kod nie chce tego poprawnie załadować? Faktycznie w edytorze jest ok, ale kod wariuje.
stryku
Pokaż mi kod, który nie chce tego poprawnie załadować
Endrju
  • Rejestracja:około 22 lata
  • Ostatnio:ponad rok
2

Przecież te wszystkie kody działają od pierwszego posta. Od zawsze działały.

Plik binarny należy otworzyć hexedytorem a nie notatnikiem. Ile razy można to pisać?

Jeżeli nadal coś nie działa pokaż cały oryginalny kod a nie jakiś przykładowy fragment.


"(...) otherwise, the behavior is undefined".
edytowany 2x, ostatnio: Endrju
TM
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 9 lat
  • Postów:11
0

Otworzyłem, dla zapisanej jedynki jest okej.

Teraz zapiszcie sobie tymi kodami dwójkę, plik będzie pusty, a ja mam związane ręce:
http://scr.hu/5icj/rf53g

EDIT: Dobra, all działa, dziwne, że kod pusty plik jednak odczytuje lel. Dziękuję wszystkim za pomoc.

Teraz pytanie: Jak zakodować zapisane dane, aby nikt ich nie odczytał, ewentualnie zabezpieczyć przed edycją (np. po edycji save się nie załaduje)

edytowany 1x, ostatnio: TurboMen
stryku
Ja odpadam. Jeżeli nie jesteś trollem to ja bym to zaliczył do perełek
grzesiek51114
grzesiek51114
Przecież to jest binarny plik! Otwieraj takie coś heksaedytorami!!!! @Shalom!!!
TM
Oj kocham Was xD - dzięki za pomoc, ale jak zepsuć tego save, jak ktoś go zedytuje?
grzesiek51114
grzesiek51114
@TurboMen Odpowiadam: Otwórz plik kernel32.dll, zmień jeden z heksów i zrestartuj system. :P W taki sam sposób popsujesz sobie swojego sejwa. Jak ktoś świadomie zmieni zawartość pliku to nie ma rady przecież. No chyba, że ktoś wie co edytuje. Otwórz heksaedytor i zmień tego inta coś go zapisał. Zobaczysz, że odczyta się właśnie ten int. Tylko błagam... w odpowiedniej kolejności w mainie. :)
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
2

Dobra, all działa, dziwne, że kod pusty plik jednak odczytuje lel. Dziękuję wszystkim za pomoc.

Ten plik nie jest pusty tylko Ty nie rozumiesz o co chodzi w zapisie binarnym.

Teraz pytanie: Jak zakodować zapisane dane, aby nikt ich nie odczytał

Zaszyfruj.

edytowany 1x, ostatnio: grzesiek51114
_13th_Dragon
  • Rejestracja:ponad 19 lat
  • Ostatnio:2 miesiące
1
TurboMen napisał(a):

Teraz zapiszcie sobie tymi kodami dwójkę, plik będzie pusty, a ja mam związane ręce:
http://scr.hu/5icj/rf53g
Ile razy ci trzeba powtórzyć aby zrozumiałeś, plik binarny nie możesz oglądać notatnikiem!
Jest tam zapisana ta dwójka.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
TM
Nie otwierałem notatnikiem, edytorem. Wszystko w porządku już teraz.
grzesiek51114
grzesiek51114
plik binarny nie możesz oglądać notatnikiem! - możesz tylko niczego sensownego nie odczytasz :P
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)