Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 16

Discussione: [C++] File (binari)

  1. #1
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177

    [C++] File (binari)

    Scrivo per una domanda di tipo generale, non legata a un problema specifico ma alla mancanza di esperienza: della serie che non chiedo righe di codice o che metodo impiegare per fare xxx, ma semplicemente il flusso di operazioni che solitamente si segue durante le operazioni su file,
    per evitare malfunzionamenti legati a file gia aperti, file inesistenti, gestione errori durante le operazioni (cosa tenere sotto controllo che puo andare storto), scrittura fallita perche' il file e' impostato dal sistema operativo in sola lettura, fine dello spazio su disco, oppure lettura fallita perche' il file e' corrotto, o che ne so....

    Ho messo tra parentesi binari in quanto a me serve per quel tipo di file, ma credo che le considerazioni siano identiche per entrambi i tipi di file, salvo venir smentito da chi ne sa piu di me...

    Mi rendo conto che la domanda e' molto estesa, grazie in anticipo a chiunque dara' il suo contributo.

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,462
    In effetti la domanda è vaga.

    Puoi fare i controlli sul buon esito di ogni funzione coinvolta, dall'apertura del file, la scrittura/lettura, la chiusura.
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Quote Originariamente inviata da oregon Visualizza il messaggio
    In effetti la domanda è vaga.
    Cerco allora di essere piu' preciso.

    All'inizio devo sempre aprire il file, le operazioni dovrebbero essere queste (il codice sotto e' preso da cplusplus)

    codice:
    #include <iostream>     // std::cout
    #include <fstream>      // std::fstream
    
    int main () {
      std::fstream fs;
      fs.open ("test.txt");
      if (fs.is_open())
      {
        fs << "lorem ipsum";
        std::cout << "Operation successfully performed\n";
        fs.close();
      }
      else
      {
        std::cout << "Error opening file";
      }
      return 0;
    }
    ma se "test.txt" e' gia aperto da qualcun altro, fs.open dovrebbe fallire, e fs.is_open dovrebbe restituire valore 'false'.

    In un caso del genere, posso solamente visualizzare che e' impossibile aprire il file, come da esempio riportato e come ho sempre trovato in utti gli esempi presenti in rete, e quindi io che uso il programma mi arrangio per i fatti miei a chiudere il processo che usa il file, oppure si puo' fare altro?

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Dipende. Gli stream C++ o la fopen() del C non gestiscono la condivisione granulare del file, ossia ciò che viene creato è sempre condiviso in lettura/scrittura. Pertanto se quel "test.txt" è stato creato con roba standard, non c'è modo di testare se tale filè già aperto da qualcun altro. fs.open() e fs.is_open() fanno riferimento solo allo stream corrente. E cosa importante, non c'è modo di recuperare il descrittore del file.

    Se vuoi avere un po' di granularità devi scendere di un livello e usare le funzioni di basso livello del C. Per Windows le puoi trovare qui:
    https://msdn.microsoft.com/en-us/library/40bbyw78.aspx
    i nomi credo non si discostino dallo standard POSIX. Occhio però che i flag sono diversi da quelli standard.

    In alternativa puoi usare direttamente le API, a partire da CreateFile().
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  5. #5
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Quote Originariamente inviata da shodan Visualizza il messaggio
    Dipende. Gli stream C++ o la fopen() del C non gestiscono la condivisione granulare del file, ossia ciò che viene creato è sempre condiviso in lettura/scrittura. Pertanto se quel "test.txt" è stato creato con roba standard, non c'è modo di testare se tale filè già aperto da qualcun altro. fs.open() e fs.is_open() fanno riferimento solo allo stream corrente. E cosa importante, non c'è modo di recuperare il descrittore del file.

    Se vuoi avere un po' di granularità devi scendere di un livello e usare le funzioni di basso livello del C. Per Windows le puoi trovare qui:
    https://msdn.microsoft.com/en-us/library/40bbyw78.aspx
    i nomi credo non si discostino dallo standard POSIX. Occhio però che i flag sono diversi da quelli standard.

    In alternativa puoi usare direttamente le API, a partire da CreateFile().
    Pensavo ci fosse qualcosa di piu' immediato, quindi tenendo presente che l'utente finale è il sottoscritto e che i file da gestire sono necessari solo al programma che tenta di leggerli / scriverli, l'evento da me ipotizzato, file gia in uso, inizia ad essere abbastanza remoto, e comunque, al massimo mi arrabbiero' con me stesso. Tengo comunque presente quanto consigliato, quando ci sara' tempo (???), gli daro' una guardata, per ora mi preme chiarirmi le idee sul resto delle operazioni.

    Mi restano in sospeso la lettura e la scrittura.

    Dalla lettura della documentazione, se non ho capito male, entrambe dovrebbero essere operazioni che non invalidano l'oggetto stream, che sta svolgendo l'operazione, ma settano i flag interni a valori che descrivono quanto successo.

    Stando cosi le cose, finita la scrittura, verifico che il / i flag siano 'a posto', nel caso di lettura, piu o meno idem, cioe' faccio l'operazione di lettura in una variabile temporanea, verifico i flag dello stream per avere conferma che l'operazione sia avvenuta con successo, quindi copio il valore nella variabile vera e propria.

    Se le cose stanno cosi', nell'ipotesi di una sequenza di read / write a seconda dell'operazione che si sta effettuando, ad esempio devo leggere / scrivere un char, un double, una stringa, effettuo il controllo del / dei flag opportuni dopo ogni singola operazione o alla fine della catena di operazioni?

    In attesa di conferme, smentite, chiarimenti, vado a guardare nuovamente la documentazione, in modo da scrivere qualche riga di codice a favore anche di altri che eventualmente leggeranno in futuro.
    Ultima modifica di ing82; 14-03-2017 a 19:12

  6. #6
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Dalla lettura della documentazione, se non ho capito male, entrambe dovrebbero essere operazioni che non invalidano l'oggetto stream, che sta svolgendo l'operazione, ma settano i flag interni a valori che descrivono quanto successo.
    Non è esatto. Se l'operazione lettura/scrittura fallisce per qualche motivo, i flag interni passano da .good() a qualcosa che può essere eofbit(), badbit() o failbit() a seconda dei casi, ma l'intero stream è invalidato e ogni operazione successiva di lettura / scrittura fallisce.
    Stando cosi le cose, finita la scrittura, verifico che il / i flag siano 'a posto', nel caso di lettura, piu o meno idem, cioe' faccio l'operazione di lettura in una variabile temporanea, verifico i flag dello stream per avere conferma che l'operazione sia avvenuta con successo, quindi copio il valore nella variabile vera e propria.
    La variabile temporanea è solo una perdita di tempo. Se la lettura avviene con successo, i dati sono immediatamente disponibili; se c'è un fallimento non li hai proprio.
    Il controllo puoi sempre farlo alla fine, ma se vuoi farlo man mano nulla te lo vieta. A quel punto però forse converrebbe abilitare le eccezioni per lo stream ed evitare un sacco di if.
    Detto molto in breve. O va o non va: non esiste un va così così.
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  7. #7
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Credo allora di aver interpretato male la seguente frase, che viene riportata identica sia per il metodo write che per il metodo read:

    "Basic guarantee: if an exception is thrown, the object is in a valid state.
    It throws an exception of member type failure if the resulting error state flag is not goodbit and member exceptions was set to throw for that state.
    Any exception thrown by an internal operation is caught and handled by the function, setting badbit. If badbit was set on the last call to exceptions, the function rethrows the caught exception."

    Io l'avevo interpretata come "se qualcosa va male, l'oggetto stream resta sempre in uno stato valido, nel senso che posso comunque sapere cosa e' successo mediante i flag interni, da interrogare mediante gli appositi metodi." (non e' una traduzione letterale, ma quanto ho interpretato io).

    Appena riesco scrivo qualche riga di codice. Grazie.

  8. #8
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Quote Originariamente inviata da shodan Visualizza il messaggio
    La variabile temporanea è solo una perdita di tempo. Se la lettura avviene con successo, i dati sono immediatamente disponibili; se c'è un fallimento non li hai proprio.
    Il controllo puoi sempre farlo alla fine, ma se vuoi farlo man mano nulla te lo vieta.
    Io pensavo al seguente caso.

    codice:
    class ProvaFile
    {
      public:
        //metodi vari
        void save(std::ofstream& file) const
        {
          file.write(reinterpret_cast<const char*>(&mDato1), sizeof(mDato1);
          file.write(reinterpret_cast<const char*>(&mDato2), sizeof(mDato2);
          file.write(reinterpret_cast<const char*>(&mDato3), sizeof(mDato3);
        };
    
        void read(std::ifstream& file)
        {
          file.read(reinterpret_cast<const char*>(&mDato1), sizeof(mDato1);
          file.read(reinterpret_cast<const char*>(&mDato2), sizeof(mDato2);
          file.read(reinterpret_cast<const char*>(&mDato3), sizeof(mDato3);
        };
    
      private:
        
        Tipo1 mDato1;
        Tipo2 mDato2;
        Tipo3 mDato3;
    
    };
    Se la lettura fallisce dopo aver letto il primo dato, quindi mentre cerca di leggere il secondo, mi trovo l'oggetto che e' in uno stato incoerente, ecco perche' dicevo di leggere in variabili temporanee, e poi, verificato che la lettura sia andata a buon fine, copiare i dati letti nei dati membro dell'oggetto.

    Quote Originariamente inviata da shodan Visualizza il messaggio
    A quel punto però forse converrebbe abilitare le eccezioni per lo stream ed evitare un sacco di if.
    Perdona l'ignoranza, ma come si fa? Sta forse scritto nei volumi sugli stream che gia' mi avevi consigliato? Grazie.

  9. #9
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Si, capisco la tua perplessità. Ma se tutti e tre i dati sono necessari, basta che uno solo non sia letto correttamente per rendere incoerente l'oggetto; a meno che i tre dati non abbiano un valore di default da ripristinare in seguito a un fallimento.
    Facciamo una mera ipotesi: la prima lettura riesce, la seconda no, la terza misteriosamente si. Il tuo oggetto sarebbe coerente (a prescindere dalle variabili temporanee che poi assegni in caso la lettura riesca)?
    Inoltre, se le letture non riescono e l'oggetto è coerente, è usabile?
    E' corretto usare variabili temporanee in lettura (il mio commento di prima si riferiva a un caso triviale), pero' bisogna anche vedere in concreto di cosa si parla. Altrimenti ci si perde in troppi forse e troppi ma.

    Perdona l'ignoranza, ma come si fa?
    Qui c'è l'esempio. Basta impostare i flag che si vogliono controllare.
    http://en.cppreference.com/w/cpp/io/...ios/exceptions
    This code and information is provided "as is" without warranty of any kind, either expressed
    or implied, including but not limited to the implied warranties of merchantability and/or
    fitness for a particular purpose.

  10. #10
    Utente di HTML.it L'avatar di ing82
    Registrato dal
    Sep 2014
    Messaggi
    177
    Tenendo sempre presente che l'utente finale sono io stesso, direi che allora posso affrontare il problema in questo modo:

    All'apertura del file, verifico che sia stato effettivamente aperto, con istruzioni simili a queste:
    codice:
      std::fstream fs;//faro' ifstream o ofstream in base alle necessita'
      fs.open ("test.txt");//ci posso aggiungere la modalita' di apertura
      if (fs.is_open())
      {
        //quello che devo fare
        fs.close();
      }
      else
      {
        std::cout << "Error opening file";
      }
    Per la scrittura quindi potrei fare

    codice:
      fs.write(/*scrittura 1*/);
      fs.write(/*scrittura 2*/);
      //elenco di tutto quello che devo scrivere
      if(fs.good())
      {
        std::cout<<"Scrittura avvenuta con successo";
      }
      else
      {
        std::cout<<"Lettura fallita";
      }
    Per la lettura, una cosa simile,
    codice:
      fs.read(/*lettura1*/);
      fs.read(/*lettura2*/);
      fs.read(/*letturan*/);
      if(fs.good())
      {
        std::cout<<"Lettura avvenuta con successo";
      }
      else
      {
        std::cout<<"Lettura fallita";
        //decido se ripristinare i valori di default nel caso di un oggetto, ripristinare i valori precedenti o non so che altro, in base al caso specifico
      }
    Cosi' facendo sono nella condizione di sapere almeno se tutto e' andato bene o no.
    In questo modo comunque non dovrei avere blocchi durante l'esecuzione, approfondiro' poi con maggior calma tutto il resto.

    Ultima cosa: quanto scritto in precedenza, come mia interpretazione, e' corretto?

    Mi autoquoto:

    Credo allora di aver interpretato male la seguente frase, che viene
    riportata identica sia per il metodo write che per il metodo read:



    "Basic guarantee: if an exception is thrown, the object is in a valid state.

    It throws an exception of member type failure if the resulting error state flag is not goodbit and member exceptions was set to throw for that state.

    Any exception thrown by an internal operation is caught and handled by the function, setting badbit. If badbit was set on the last call to exceptions, the function rethrows the caught exception."



    Io l'avevo interpretata come "se qualcosa va male, l'oggetto stream resta sempre in uno stato valido, nel senso che posso comunque sapere cosa e' successo mediante i flag interni, da interrogare mediante gli appositi metodi." (non e' una traduzione letterale, ma quanto ho interpretato io).

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.