{c++}Jak zapisać wartości bez zaczepiana innych bajtów?

0

Stworzyłem program który wczytuje plik z dwiema strukturami, ale teraz uwaga. Nie ma całkowitej struktury pliku, po prostu wszystko wynika samo z siebie. W pierwszej strukturze jest wartość na który offset ma przejść wskaźnik, i tutaj się wczytuje druga struktura, i ona się jeszcze zapętla ponieważ w pierwszej strukturze jest jeszcze napisane ile razy ona się powtarza po sobie. No ale pomiędzy tymi dwoma strukturami są ważne dane, do których zbytnio nie chce mi się struktur pisać. No i teraz ja chciałbym w pierwszej strukturze zmienić pierwszą wartość, i zapisać, ale tak żeby pozostałe bajty zostały nie tknięte. Już troszkę się naszukałem rozwiązania, ale właśnie nie mogę znaleźć.
Bo jeśli zapiszę czymś takim:
(przykład z Odczyt i zapis plików binarnych w Cpp)

ofstream ofs("plik.foo", ios::binary); // otwieramy plik do zapisu binarnego

File* file = new File;
cin >> file->number1 >> file->number2 ;
ofs.write((char*)(file), sizeof(File)); // zapisujemy dane do pliku

To tutaj trzeba przy zapisie określić strukturę i tylko ją zapisze.

0

Tak się nie robi poczytaj o dopełnianiu pól i serializacji.

0

Czy możesz konkretnie powiedzieć co próbujesz osiągnąć?

0

Dokładnie to próbuję zrobić konwerter modeli z jednej gry do gry. W hex editor wszystko wiem jak zrobić i ja tylko bajty przerabiam, a teraz chcę stworzyć program który sam mi to zrobi. No i w tym momencie pozostaje pytanie jak zmienić np. 4 bajty które są oparte na strukturze i je zmienić i zapisać nie zmieniając pozostałych bajtów.

0

fds, jakiś tutotrial po polsku dot. serializacji?

0

Teoretycznie to co robisz jest poprawne. Może błąd w innym miejscu.

0

Teoretycznie to chodzi tu tylko o tą linijke:
ofs.write((char*)(file), sizeof(File)); // zapisujemy dane do pliku
Bo tutaj trzeba podać sizeof(File). Tak jakby się nie dało po prostu przyjąć np.
struct example
{
long a;
};
// odczyt pliku do zapisu
a = 5
plik.write((char*)(xxx), sizeof(xxx));

Ale jeśli w pliku mam 8 bajtów a ja chce zamienić 4 pierwsze, na liczbę dziesiętną 5. No i co wtedy. xxx to są miejsca w których trzeba coś wpisać, tylko właśnie co.

Jeśli potrzeba podam cały kod programu.

0
int a = 5;
plik.write((char*)&a,sizeof(int));
//lub to co będzie ci chyba bardziej pasowało.
char b[]={5,0,0,0};
plik.write(b,sizeof(b));
0

No ale widzisz, i znowu pierwszy bajt jest taki jaki powinien być ale inne inne zostały usunięte.

0

Może nadal nikt nie rozumie. Chodzi oto że ja już mam plik. Pozostaje go tylko przerobić. Program ma wczytać plik, i zmienić mu np. pierwsze 4 bajty nie naruszając innych bajtów. I zapisać. Z resztą to ja już sobie poradzę.

0

A nie możesz po prostu wczytać do tablicy char zamienić, co trzeba i zapisać do pliku?

0

Że cały plik wczytać do char, i go zapisać?

0

Tak będzie najprościej, z tym że zmapuj go strukturami.
char *bufor=new char[filesize];
file.read(bufor,filesize);
struct Poczatek{ ... };
Poczatek P=(Poczatek)bufor;
struct Srodek{ ... };
Srodek S=(Srodek)(P+1);
struct Koniec{ ... };
Koniec K=(Koniec)(S+IleJestTychSrodkow);

teraz zmieniasz sobie co chcesz:
P->dane1=...;
for(int i=0;i<IleJestTychSrodkow;++i) S[i] dane2=...;
K->dane3=...;

No i na koniec zapisujesz z powrotem bufor.

0

Jeżeli znasz położenie podmienianych bajtów w pliku możesz zrobić to bezpośrednio. Ale łatwo przy tym coś namieszać.

0

Tak, znam pozycje tego czego mam zmienić. To nie problem, ale powiedz mi jak to zrobić. Tego sposobu co dał _13th_Dragon spróbuję i zobaczymy ;)-

0

@recman miał na myśli to co ci już mówiłem:

char b[]={5,0,0,0};
plik.seekp(pozycja,ios::beg);
plik.write(b,sizeof(b));

O ile masz do zmiany tylko jedną czy dwie wartości i nie jest nawet planowane dodatkowe wartości to taka metoda ujdzie.

0

Albo nie umiem czytać ze zrozumieniem i słońce na mnie dzisiaj źle podziałało, albo w VS 2010 jest jeden wielki WTF(nie sprawdzałem na innych kompilatorach)
Przy otwieraniu pliku jeżeli nie da się flagi ios::app to zawsze plik jest czyszczony. W momencie dodania flagi app zawartość wprawdzie czyszczona nie jest, ale można TYLKO dopisywać do pliku. Metoda seekp jest po prostu bezczelnie ignorowana.

0

_13th_Dragon, dla testu stworzyłem nowy program, testujący twój sposób, ale czegoś tutaj nie rozumiem, czy to miałoby wyglądać tak:

#include <fstream>
#include <iostream>

using namespace std;
struct Poczatek{
long dane1;
};
struct Srodek{
long dane2;
};
struct Koniec{
long dane3;
};

int main()
{
ifstream file("plik.bin", ios::binary);

int filesize = 70;
char *bufor=new char[filesize];
file.read(bufor,filesize);
Poczatek P=(Poczatek)bufor;
Srodek S=(Srodek)(bufor+sizeof(Poczatek));
Koniec K=(Koniec)(S+1);
P->dane1= 5;
for(int i=0;i<434;++i) S[i];
K->dane3=7;

ofstream file2("plik.bin", ios::binary);
file2.write((char*)(bufor), sizeof(filesize));
}

0
int main()
  {
   fstream file("plik.bin",ios::in|ios::out|ios::binary);
   file.seekg(0,ios::end);
   unsigned filesize=tellg();
   char *bufor=new char[filesize];
   file.seekg(0,ios::beg);
   file.read(bufor,filesize);
   file.seekg(0,ios::beg);
   unsigned IleS=(filesize-sizeof(Poczatek)-sizeof(Koniec))/sizeof(Srodek);
   if(sizeof(Poczatek)+IleS*sizeof(Srodek)+sizeof(Koniec)!=filesize)
     {
      cerr<<"Nieodpowiednie struktury"<<endl;
      exit(1);
     }
   Poczatek *P=(Poczatek*)bufor;
   Srodek *S=(Srodek*)(bufor+sizeof(Poczatek));
   Koniec *K=(Koniec*)(S+IleS);
   P->dane1=5;
   for(int i=0;i<IleS;++i) S[i]->dane2=i+100;
   K->dane3=7;
   file.seekp(0,ios::beg);
   file.write(bufor,filesize);
   file.close();
   cout<<"Wykonano"<<endl;
   return 0;
  }
0

Poradziłem sobie troszeczke inaczej:
#include <fstream>
#include <iostream>
using namespace std;
struct struktura1{
long dane1;
};
struct struktura2{
long dane2;
long dane3;
};

int main()
{
unsigned long long rozmiar;
int a,b,c;

fstream plik("plik2.bin",ios::in|ios::out|ios::binary);
if(plik){
plik.seekg( 0, ios::end );
rozmiar = plik.tellg();
plik.seekg( 0, ios::beg );
cout << "Rozmiar pliku to: " << rozmiar << " Bajtow"<< endl;
}

char *bufor=new char[rozmiar];
plik.seekg(0,ios::beg);
plik.read(bufor,rozmiar);
plik.seekg(0,ios::beg);
struktura1 P=(struktura1)bufor;
struktura2 K=(struktura2)(4+bufor); // 4 bajty +
K->dane2=5432;
P->dane1=1200;

// plik.seekp(0,ios::beg);
plik.write(bufor,rozmiar);

  system("pause");

return (0);
}

Wtedy strukture 2 mogę określić dokładnie gdzie ma być. Jeśli jest potrzeba powtarzania jej po sobie kilka krotnie to wtedy taka pętla:

#include <fstream>
#include <iostream>
using namespace std;
struct struktura1{
long dane1;
};
struct struktura2{
long dane2;
long dane3;
};

int main()
{
unsigned long long rozmiar;
int a,b,c;
a=0;
b=3;
c=0;

fstream plik("plik2.bin",ios::in|ios::out|ios::binary);
if(plik){
plik.seekg( 0, ios::end );
rozmiar = plik.tellg();
plik.seekg( 0, ios::beg );
cout << "Rozmiar pliku to: " << rozmiar << " Bajtow"<< endl;
}

char *bufor=new char[rozmiar];
plik.seekg(0,ios::beg);
plik.read(bufor,rozmiar);
plik.seekg(0,ios::beg);
struktura1 P=(struktura1)bufor;
while( a < b ) // przykładowy warunek aby się powtarzało 3 razy.
{
a++;
c=c+4;
struktura2 K=(struktura2)(c+bufor);
K->dane2=5432;
}
P->dane1=1200;

plik.write(bufor,rozmiar);

  system("pause");

return (0);
}

Dzięki za pomoc :)

0

To bez sensu zrobiłeś. Dokładnie to samo można zrobić tak, bez struktur:

long *P=(long*)bufor;
long *K=P+1;
for(int i=0;i<3;++i) // przykładowy warunek aby się powtarzało 3 razy.
  {
   K[i]=5432;
  }
*P=1200;
0

Ale mi właśnie trzeba struktury :P Ja na podstawie struktur określam co zmieniam :)

0

Coś namieszałeś. Dlaczego zwiększasz offset o 4 skoro struktura2 to 8 bajtów. W ogóle nie powinieneś podawać tych offsetów ręcznie. Rozumiem, że w pliku na początku znajduje się struktura1 a za nią tablica struktur struktura2. Więc użyj mniej więcej takiego kodu:

// na początku pliku jedna strukturka "struktura1"
struktura1 *P=(struktura1*)(bufor + 0); // "+0" jest tu jedynie dla zwiększenia czytelności
P->dane1=1200;

// później tablica strukturek "struktura2", w pliku znajduje się za jedną strukturką "struktura1"
struktura2 *K=(struktura2*)(bufor + sizeof(struktura1)); // !!!
for (int i = ... ){
        K[i].dane2=5432;
        }
0
adf88 napisał(a):
// na początku pliku jedna strukturka "struktura1"
struktura1 *P=(struktura1*)(bufor + 0); // "+0" jest tu jedynie dla zwiększenia czytelności
P->dane1=1200;

// później tablica strukturek "struktura2", w pliku znajduje się za jedną strukturką "struktura1"
struktura2 *K=(struktura2*)(bufor + sizeof(struktura1)); // !!!
for (int i = ... ){
        K[i].dane2=5432;
        }

Podałem mu to kilka postów wcześniej w takiej formie:

struktura1 *P=(struktura1*)bufor;
P->dane1=1200;
struktura2 *K=(struktura2*)(P+1);
for (int i = ... ) K[i].dane2=5432;

To co widzisz to jest wynik jego adaptacji :D

0

Jeśli będą jeszcze jakieś dodatkowe struktury w plik (za tablicą K) to może lepiej będzie użyć takiego schematu:

// na początku pliku jedna strukturka "struktura1"
struktura1 *P=(struktura1*)bufor;
bufor += sizeof(struktura1);

P->dane1=1200;
 
// później tablica strukturek "struktura2", w pliku znajduje się za jedną strukturką "struktura1"
struktura2 *K=(struktura2*)bufor;
bufor += sizeof(struktura2) * ilosc_struktur_w_tablicy_K;

for (int i = ... ){
        K[i].dane2=5432;
        }

// i później np. jedna struktura "struktura3"
struktura3 *S=(struktura3*)bufor;
bufor += sizeof(struktura3);

...

czyli za każdym razem przesuwamy wskaźnik bufor za to, co już odczytaliśmy, a przed tym, czego jeszcze nie.

0
adf88 napisał(a):

Widać, że nie zrozumiałeś idei. Chodzi o przesuwanie "wskaźnika odczytu".

Idea jest bombowa, tylko że:

  1. bufor przydzielany jest dynamicznie, więc delete na końcu zrobi kuku.
  2. proponujesz zastąpienie tego:
struktura3 *S=(struktura3*)(K+ilosc_struktur_w_tablicy_K);

tym:bufor += sizeof(struktura2) * ilosc_struktur_w_tablicy_K;
struktura3 S=(struktura3)bufor;

0
  1. Problem nie dotyczy snippeta który podałem. Wiadomo, że trzeba zwalniać to co się przydzieliło.
  2. Tak. O to właśnie chodzi.
0

Jakoś zrobiłem po swojemu, i sprawuje się nieźle. Ja nie zmieniam rozmiaru pliku. W tej chwili powinno tak zrobić ale nie robi, wydaje mi się że po zrobieniu reada, i podaniu w nim rozmiaru rozmiaru już się nie zmieni, próbując wieloma sposobami. A więc jeśli dodam do bufora liczbę to mi przesunie strukture o tyle ile chcę, np. nie tracąc danych w środku i nie pisząc środkowej strukutry. Robiąc to: for (int i = ... ) K[i].dane2=5432; Po prostu mi nie kompilowało. Czemu, nie wiem.

1
Mojżesz napisał(a):

Robiąc to: for (int i = ... ) K[i].dane2=5432; Po prostu mi nie kompilowało. Czemu, nie wiem.
Aż się chce krzyknąć AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA! K.... chwyć że jakiś kurs podstaw.

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