Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++, fstream] Jednoczesne wczytywanie i zapisywanie danych w pliku

Ostatnio zmodyfikowano 2013-11-27 13:12
Autor Wiadomość
Mr.J
Temat założony przez niniejszego użytkownika
[C++, fstream] Jednoczesne wczytywanie i zapisywanie danych w pliku
» 2013-11-24 20:12:41
Witam, przeczytalem na pewnej stronie ze mozliwe jest przeprowadzenie jednoczesnie operacji zapisu/wczytania danych z/do pliku otwierajac go w ten sposob:
C/C++
...
std::fstream mapData;
mapData.open(( "Maps/" + mapName + ".Pg" ).c_str(), std::ios::binary | std::ios::in | std::ios::out );
...
...jednak wydaje mi sie ze wtedy funkcja read nie pobiera zadnych danych.

Oto caly kod:
C/C++
int MapManager::save_sector( int sector_x, int sector_y, int offset_x, int offset_y )
{
   
    if( sector_x >= 0 && sector_x < number_of_x_sectors
    && sector_y >= 0 && sector_y < number_of_y_sectors )
    {
        //-------------------------------------------------------------TWORZENIE BUFORA----//
        std::fstream mapData;
        mapData.open(( "Maps/" + mapName + ".Pg" ).c_str(), std::ios::binary | std::ios::in | std::ios::out );
        if( !mapData )
        {
            return - 1;
        }
       
        //-----OKRESLENIE ROZMIARU PLIKU-----//
        mapData.seekg( 0, mapData.end );
        long length = mapData.tellg();
        mapData.seekg( 0, mapData.beg );
       
        //-----------ALOKACJA PAMIECI----------//
        char * buffer = new char[ length ];
       
        //-------------ZAPIS DO BUFORA---------//
        mapData.read( buffer, length );
       
        //---------------------------------------------------------------ZAPIS Z BUFORA-----//
       
        //-------USTAWIENIE WSKAZNIKA NA ODPOWIEDNI SEKTOR-------------//
        long g_possition = 0;
       
        //----DLUGOSC DANYCH MAPY----//
        int mapData_size = 0;
        mapData.read(( char * ) & mapData_size, sizeof( int ) );
        g_possition += sizeof( int ) + mapData_size;
        mapData.seekg( g_possition );
       
        //-------DLUGOSC POPRZEDNICH SEKTOROW(W SUMIE)-------------//
        long sector_size = 0;
        for( int i_sector = 0; i_sector < sector_y * number_of_x_sectors + sector_x; i_sector++ )
        {
            if( g_possition + 3 >= length )
                 return - 11;
           
            mapData.read(( char * ) & sector_size, sizeof( long ) );
           
            g_possition += sizeof( long ) + sector_size;
            mapData.seekg( g_possition );
        }
       
        flag_Set tempFlag = { 1, 1, 1, 1, 0 };
        signed int tempID = - 1;
        std::vector < OBJinfo > tempInfo;
        int square_size = 0;
        char empty_info = 'E';
       
        //------------ZAPIS AKTUALNEGO SEKTORA--------------//
        //---pomijanie rozmiaru sektora---//
        long temp_g = g_possition;
        g_possition += sizeof( long ); //<-----tutaj jest cos nie tak
        mapData.seekp( g_possition );
       
        for( int iPlane = 0; iPlane < 2; iPlane++ ) //poziomy
        {
            for( int i = 0; i < TILES_PER_SECTOR; i++ ) //kafelki w osi y
            {
                for( int j = 0; j < TILES_PER_SECTOR; j++ ) //kafelki w osi x
                {
                    //tempFlag = myTile[iPlane][i + offset_y][j + offset_x].get_flag();
                    tempID = objSlot[ iPlane ][ i + offset_y ][ j + offset_x ].get_ID();
                    tempInfo = objSlot[ iPlane ][ i + offset_y ][ j + offset_x ].get_info();
                   
                    if( tempInfo.size() > 0 )
                    {
                        square_size = 24 + sizeof( tempInfo.at( 0 ) );
                    }
                    else
                         square_size =( sizeof( int ) * 6 + sizeof( char ) );
                   
                    mapData.write(( char * ) & square_size, sizeof( int ) );
                    mapData.write(( char * ) & tempFlag, sizeof( int ) * 5 );
                    if( i == 0 && j == 0 && iPlane == 0 )
                    {
                        //-------------------------------------------------------------------------------<-- tutaj przeprowadzilem test
                        int test_int = 5;
                        mapData.seekg( g_possition + sizeof( int ) );
                        mapData.read(( char * ) & test_int, sizeof( int ) ); //---------------------------------<-- w 99% przypadkow powinienem tu pobierac wartosc "2"
                        std::ofstream test1;
                        test1.open( "test zmiennej.txt" );
                        test1 << test_int; //----------------------------------------------------------<-- tutaj zawsze otrzymuje wartosc 5, czemu?           
                        test1.close();
                    }
                    mapData.write(( char * ) & tempID, sizeof( int ) );
                    if( tempInfo.size() > 0 )
                         mapData.write(( char * ) & tempInfo[ 0 ], sizeof( tempInfo[ 0 ] ) );
                    else
                         mapData.write(( char * ) & empty_info, sizeof( char ) );
                   
                    sector_size +=( sizeof( int ) + square_size );
                }
            }
        }
        //---ZAPIS ROZMIARU SEKTORA---//
        mapData.seekp( temp_g );
        mapData.write(( char * ) & sector_size, sizeof( long ) );
        g_possition += sector_size;
        mapData.seekp( g_possition );
       
        //-----------ZAPIS POZOSTALYCH SEKTOROW-------------------//
        mapData.write(( char * ) & buffer[ g_possition ], length - g_possition ); //?
        delete[] buffer;
        buffer = NULL;
       
        mapData.close();
    }
    return 0;
}
 
Dodam jeszcze ze calosc sie kompiluje ale w grze wyglada to tak ze po "aktualizacji" sektorow wszystko wraca do wartosci poczatkowych czyli nic nie zostaje zapisane :/

PS. Zapomnialem dodac ze wiem ze miejsca gdzie pojawia sie vector<OBJinfo> sa blednie napisane, ale moj program nie obsluguje w tej chwili tych przypadkow wiec nie stanowia one problemu i nie pokusilem sie o ich poprawienie :P
P-97390
DejaVu
» 2013-11-27 03:56:07
Napisz prostszy program do przetestowania 'jednoczesnego' odczytu i zapisu do pliku. Chociażby coś podobnego do tego:
C/C++
char tablica[ 50 ] = "abc";
plik.write( tablica, 3 );
plik.read( tablica + 3, 3 );
tablica[ 6 ] = 0;
N-lat temu też próbowałem jednoczesny odczyt i zapis do pliku na fstream-ie i jakoś mi wtedy nie wychodziło. Napisz maksymalnie krótki program weryfikujący Twoje pytanie, wklej go i podziel się swoimi obserwacjami. Być może wówczas ktoś zweryfikuje poprawność Twojego rozwiązania i da Ci ostateczną odpowiedź, popartą np. dokumentacją, standardem czy też większym doświadczeniem.
P-97635
Mr.J
Temat założony przez niniejszego użytkownika
» 2013-11-27 10:11:42
Witam, wczoraj udalo mi sie wreszcie rozwiazac problem, na moje szczescie bylem na tyle zdesperowany ze probowalem wszystkiego...okazalo sie ze (nie do konca rozumiem czemu) w przypadku fstream'a trzeba uzywac jednoczesnie funkcji seekg i seekp niezaleznie od tego czy wczytujemy czy zapisujemy. Po wstawieniu tych dwoch funkcji jednoczesnie obok siebie wszystko zaczelo dzialac(musialem tez usunac ten fragment testujacy tamta zmienna). Dodam jeszcze ze po uruchomieniu gry dotralo do mnie ze cala operacja kopiowania danych do bufora jest zbedna, bo jedynie podmieniam fragmenty danych, a nie tworze plik od nowa.

Calosc wyglada tak: (Komentarze moga byc troche mylace dlatego nie nalezy zwracac na nie uwagi.)
C/C++
int MapManager::save_sector( int sector_x, int sector_y, int offset_x, int offset_y, bool underground )
{
   
    if( sector_x >= 0 && sector_x < number_of_x_sectors
    && sector_y >= 0 && sector_y < number_of_y_sectors )
    {
        //-------------------------------------------------------------TWORZENIE BUFORA----//
        std::fstream mapData;
        mapData.open(( "Maps/" + mapName + ".Pg" ).c_str(), std::ios::binary | std::ios::in | std::ios::out );
        if( !mapData )
        {
            return - 1;
        }
       
        //-----OKRESLENIE ROZMIARU PLIKU-----//
        mapData.seekg( 0, mapData.end );
        long length = mapData.tellg();
        mapData.seekg( 0, mapData.beg );
       
        //-----------ALOKACJA PAMIECI----------//
        //   char *buffer = new char[length];
       
        //-------------ZAPIS DO BUFORA---------//
        //   mapData.read(buffer, length);
       
        //---------------------------------------------------------------ZAPIS Z BUFORA-----//
       
        //-------USTAWIENIE WSKAZNIKA NA ODPOWIEDNI SEKTOR-------------//
        long g_possition = 0;
       
        //----DLUGOSC DANYCH MAPY----//
        int mapData_size = 0;
        mapData.seekp( 0 );
        mapData.read(( char * ) & mapData_size, sizeof( int ) );
        g_possition += sizeof( int ) + mapData_size;
        mapData.seekg( g_possition );
        mapData.seekp( g_possition );
       
        //-------DLUGOSC POPRZEDNICH SEKTOROW(W SUMIE)-------------//
        long sector_size = 0;
        long Underground_surfaceSize = 0;
        long surfaceSize = 0;
        for( int i_sector = 0; i_sector < sector_y * number_of_x_sectors + sector_x; i_sector++ )
        {
            if( g_possition + 3 >= length )
                 return - 11;
           
            mapData.read(( char * ) & sector_size, sizeof( long ) );
            if( sector_size < 59392 || sector_size > 100000 )
            {
                std::ofstream test2;
                test2.open( "test rozmiaru sektora.txt" );
                test2 << sector_size;
                test2.close();
                return - 33;
            }
           
            g_possition += sizeof( long ) + sector_size;
            mapData.seekg( g_possition );
            mapData.seekp( g_possition );
        }
        //-------------------------------------------WCZYTANIE ROZMIARU POWIERZCHNI---------------------//
        long temp_g_for_sector_size = 0;
        long temp_g_for_surface_size = 0;
        //---pozycja przed rozmiarem sektora---//
        temp_g_for_sector_size = g_possition;
       
        g_possition += sizeof( long );
        //---pozycja przed rozmiarem podziemi---//
        if( underground == true )
             temp_g_for_surface_size = g_possition;
       
        mapData.seekg( g_possition );
        mapData.seekp( g_possition );
        mapData.read(( char * ) & Underground_surfaceSize, sizeof( long ) );
        g_possition += sizeof( long ) + Underground_surfaceSize;
        //---pozycja przed rozmiarem powierzchni---//
        if( underground == false )
             temp_g_for_surface_size = g_possition;
       
        mapData.seekg( g_possition );
        mapData.seekp( g_possition );
        mapData.read(( char * ) & surfaceSize, sizeof( long ) );
       
        //ustawianie wskaznika zapisu na odpowiednia powierzchnie
        mapData.seekg( temp_g_for_surface_size + sizeof( long ) );
        mapData.seekp( temp_g_for_surface_size + sizeof( long ) );
        //-------------------------------------------------//
       
        flag_Set tempFlag = { 1, 1, 1, 1, 0 };
        signed int tempID = - 1;
        std::vector < OBJinfo > tempInfo;
        int square_size = 0;
        char empty_info = 'E';
       
        //------------ZAPIS AKTUALNEGO SEKTORA--------------//
        //---pomijanie rozmiaru sektora---//
       
        int iPlane = 0;
        if( underground == false )
             iPlane = 1;
       
        sector_size = 0;
        long newSurfaceSize = 0;
       
        for( int i = 0; i < TILES_PER_SECTOR; i++ )
        {
            for( int j = 0; j < TILES_PER_SECTOR; j++ )
            {
                tempFlag = myTile[ iPlane ][ i + offset_y ][ j + offset_x ].get_flag();
                tempID = objSlot[ iPlane ][ i + offset_y ][ j + offset_x ].get_ID();
                tempInfo = objSlot[ iPlane ][ i + offset_y ][ j + offset_x ].get_info();
               
                if( tempInfo.size() > 0 )
                {
                    square_size = 24 + sizeof( tempInfo.at( 0 ) );
                }
                else
                     square_size =( sizeof( int ) * 6 + sizeof( char ) );
               
                mapData.write(( char * ) & square_size, sizeof( int ) );
                mapData.write(( char * ) & tempFlag, sizeof( int ) * 5 );
                mapData.write(( char * ) & tempID, sizeof( int ) );
                if( tempInfo.size() > 0 )
                     mapData.write(( char * ) & tempInfo[ 0 ], sizeof( tempInfo[ 0 ] ) );
                else
                     mapData.write(( char * ) & empty_info, sizeof( char ) );
               
                newSurfaceSize +=( sizeof( square_size ) + square_size );
            }
        }
        if( underground == true )
        {
            sector_size =( sizeof( long ) * 2 + newSurfaceSize + surfaceSize );
        }
        else //underground == false
        {
            sector_size =( sizeof( long ) * 2 + newSurfaceSize + Underground_surfaceSize );
        }
        //---ZAPIS ROZMIARU POWIERZCHNI---//
        mapData.seekp( temp_g_for_surface_size );
        mapData.seekg( temp_g_for_surface_size );
        mapData.write(( char * ) & newSurfaceSize, sizeof( long ) );
        //---ZAPIS ROZMIARU SEKTORA---//
        mapData.seekp( temp_g_for_sector_size );
        mapData.seekg( temp_g_for_sector_size );
        mapData.write(( char * ) & sector_size, sizeof( long ) );
       
        //-----------ZAPIS POZOSTALYCH SEKTOROW-------------------//
        //mapData.write((char*) &buffer[g_possition], length - g_possition); //?
        // delete[] buffer;
        // buffer = NULL;
       
        mapData.close();
    }
    return 0;
}

Troche zaluje, ze nie zatytulowalem tego tematu np: "Problem z jednoczesnym zapisem i wczytywaniem danych za pomoca fstream" bo w obecnej postaci moze okazac sie malo pomocny dla kogos innego :/
Zastanawia mnie tez w jaki sposob rozwiazuje sie problem roznego rozmiaru zmiennych na roznych maszynach, bo co jezeli ktos ma na komputerze zmienna int zajmujaca 8bajtow ?
W jaki sposob poprawnie odczytac takie dane mapy? Jest jakis sposob rzutowania 4 bajtowej int na 8 bajtowa?

P-97639
pekfos
» 2013-11-27 13:12:47
Troche zaluje, ze nie zatytulowalem tego tematu np: "Problem z jednoczesnym zapisem i wczytywaniem danych za pomoca fstream" bo w obecnej postaci moze okazac sie malo pomocny dla kogos innego :/
To popraw?

Zastanawia mnie tez w jaki sposob rozwiazuje sie problem roznego rozmiaru zmiennych na roznych maszynach, bo co jezeli ktos ma na komputerze zmienna int zajmujaca 8bajtow ?
Można używać typów, których rozmiar jest stały (<cstdint>)
P-97649
« 1 »
  Strona 1 z 1