Newsgroup: it.comp.lang.c++
Titolo: file -> string

Salve.
Come posso inserire l'intero contenuto di un file in un oggetto std::string
?
Intendo dire: esiste una funzione come getline() ma che riempia una
std::string con _tutto_ il contenuto del file oppure con i primi n byte del
file stesso ?
Sottolineo: vorrei il contenuto del file _direttamente_ nella std::string e
non in un buffer di caratteri, poiché in questo caso poi dovrei copiare
l'intero buffer nella mia string che poi userò nel programma.
Grazie!
Diego.

 ?
Io farei un vector di string. Ci sono le comodità, usiamole! ;-)
Scherzi a parte, non credo sia comodo poi gestire una stringa chilometrica,
ma non so di preciso cosa devi farci, quindi può darsi che mi sbagli :-)
[CUT]
--
Ciao, _sav_

 Ciao, _sav_

 > Ciao, _sav_

 string che poi userò nel programma. Grazie!
Non esiste una tecnica che sia garantita dallo Standard, che io sappia.
Questo compila. E funziona, probabilmente, su tutte le implementazioni
esistenti. Nondimeno lo Standard non garantisce che debba funzionare.
    std::ifstream in( "file" );
    std::string data;
    data.resize( 100 );
    in.read( &*data.begin(), 100 );
Nota che se, invece, sostituisci std::string con std::vector<char>, il
codice sopra ha comportamento definito.
Max
 

 > > Ciao, _sav_

 > string che poi userò nel programma. Grazie!
...
std::string text, line;
ifstream in("miofile");
while(line = getline(in, line)) {
    text += line + '\n';
}
...
--
Domenico Testa - Studente

     in.read( &*data.begin(), 100 );
Mmmm... ahia... la soluzione è ghiotta, ma la vedo pericolosetta :) ...
comunque mi pare di aver capito che (secondo me inspiegabilmente) non esiste
una funzione che prenda tot byte da un file e li schiaffi in una string...
un vero mistero!
Ciao, Diego.

 Domenico Testa - Studente
Beh, questa soluzione la conosco, ma costringe a prendere chunk del file che
potrebbero essere troppo piccoli e quindi poco "ottimizzati" ... vorrei fare
in modo di ridurre il numero di accessi al file per velocizzare il tutto
oppure, in caso di file piccoli, mettere nella string direttamente tutto il
contenuto del file.
Grazie comunque!

 contenuto del file.
Sei cosi' sicuro di saper fare di meglio dei meccanismi di
bufferizzazione della tua piattaforma? Se si', l'unica risposta
sensata e' che tu cerchi tra i meccanismi di basso livello del tuo
sistema. L'algoritmo e':
size_t n = chiamata_di_sistema_che_ritorna_la_lunghezza_di_un_file(nome_file);
char * p = new char[n];
chiamata_di_sistema_che_legge_in_modo_efficente(p,n); (1)
Come ti ha detto Max al posto di un puntatore puoi usare un vector.
Ciao,
Nicola
(1) Ti conviene fare delle prove con meccanismi diversi: ad esempio
svolgendo un esame in universita' avevamo scoperto che su quei
particolari sistemi l'I/O su terminale era piu' efficiente usando le
primitive di sistema non bufferizzate, che non usando le funzioni di
libreria bufferizzate.

 std::string ?
uhm... subito pensavo che il seguente codice potesse funzionare:
  typedef std::istream_iterator<char> iter;
  std::ifstream file(...);
  std::string stringa; // nota che un reserve potrebbe essere utile
  std::copy( iter(file), iter(), std::back_inserter(stringa) );
putroppo istream_iterator usa l'operatore >> dello stream, per cui il 
codice qua sopra si mangia tutti gli spazi e i newline.
Una possibile soluzione e` scriversi un proprio iteratore di input che 
utilizzi get() anziche` operator>>.
ciao Anto
-- 
"Computer science is not about computers any more than astronomy
is about telescopes." -- EW Dijkstra

 Nicola
Diego.

 ciao Anto

 codice qua sopra si mangia tutti gli spazi e i newline.
istream_iterator serve per l'IO formattato (es. leggere una sequenmza
di int da un file di testo o da cin).
Per fortuna esiste anche istreambuf_iterator, che legge carattere per
carattere senza saltare niente.  Esempio:
  copy( istreambuf_iterator<char>(file),
        istreambuf_iterator<char>(),
        back_inserter(stringa) );
Questo funziona, ma non penso che sia particolarmente efficiente (i
caratteri vengono aggiunti alla stringa uno alla volta).
Altra possibilita`:
  ostringstream oss;
  oss << file.rdbuf();
  string stringa( oss.str() );
Con g++ 3.1.1 (e GNU libstdc++ fornita di serie) il secondo metodo e`
molto piu` veloce, ma le prestazioni potrebbero cambiare da un
compilatore all'altro.
        Mauro
-- 
E` in corso la votazione per creare it.sport.atletica
Se sei interessato vota su news:it.news.votazioni

         Mauro

 string ? Questa č la cosa che non mi č chiara.
In realta' esistono ulteriori alternative: ad esempio potresti
utilizzare degli stream_iterator direttamente ed evitare ogni
bufferizzazione implicita, soprattutto se lavori carattere per
carattere, o se almeno non hai bisogno di spostarti avanti o indietro.
Ciao,
Nicola

   string stringa( oss.str() );
Nei miei appunti trovo questa ulteriore possibilità:
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
void LeggiTutto( std::istream &ist, std::string &result )
{
    std::stringbuf ost( std::ios_base::out );
    ist >> ost;
    result.swap( ost.str() );
}
int main()
{
    std::ifstream ist( "LEGGI TUTTO.CC" );
    std::string s;
    LeggiTutto( ist, s );
    std::cout << s << std::endl;
}
EMG
--
EMAG Software Homepage:     
http://www.emagsoftware.it
The EMG's ZX-Spectrum Page: 
http://www.emagsoftware.it/spectrum
The Best of Spectrum Games: 
http://www.emagsoftware.it/tbosg

     in.read( &*data.begin(), 100 );
potresti avere grossi problemi nel caso in cui le stringhe siano 
implementate mediante copy-on-write. Ovviamente se 'data' e` creata sul 
momento, come nel tuo esempio, dovrebbe funzionare, pero` se 'data' e` 
una variabile copiata qua e la... bum!


 Nicola
Grazie ancora!

 
Perchè tu dal file leggi una certa sequenza di byte (che in C/C++ si
rappresentano quasi universalmente con il tipo char), e non una stringa
che è un'astrazione...per cui, se tu sei sicuro che la tua sequenza di
byte sia in realtà una sequenza di caratteri ASCII e non ad esempio un
mix di caratteri di controllo e ASCII, o peggio una sequenza binaria,
dopo averla estratta dal file e immessa in un buffer di memoria (array di
char), te la converti in string.

 'data' e` una variabile copiata qua e la... bum!
Fermo restando che, come ho detto, il funzionamento non è garantito dallo
Standard, non capisco il tuo commento. A me pare che l'unica situazione in
cui il programma possa fare "bum" sia quella in cui il riferimento a char
restituito dalla dereferenziazione dell'iteratore non identifica una
locazione appartenente ad un array scrivibile di almeno 100 caratteri.
Questo mi pare possa accadere soltanto se l'iteratore di std::string non è
un char* E il contenuto della stringa non è immagazzinato in una zona
contigua di memoria.
Max

 tradurre un concetto che mi sembra chiaro e banale.
Resta secondo me il problema fondamentale:
- Se e' una questione di efficienza, scendi di livello e sporcati le
mani;
- Se e' una questione estetica usa strumenti di alto livello ed astrai
dai
  dettagli.
Ho la sensazione che tu stia commettendo l'errore di non voler
scegliere tra queste alternative. Tra parentesi la lettura da file e'
piu' lenta della copia in memoria in termini di ordini di grandezza;
copiare qualche buffer in piu' o in meno fa poca differenza.
Ciao,
Nicola

...

Il "bum" a mio avviso non e' tanto nel codice che hai postato, quanto
nel fatto che con questa tecnica potresti sovrascrivere
accidentalmente altre stringhe che condividono la rappresentazione con
quella che stai utilizzando.
Ciao,
Nicola

 te la converti in string.
Le stringhe possono contenere qualsiasi carattere, compresi caratteri
di controllo, sequenze binarie e mix vari.
Se hai bisogno di controllare quali caratteri ci sono, puoi fare il
controllo direttamente sulla stringa.


 
Si ma usi l'operatore >>. Il quale significa "leggi dallo stream x
l'oggetto y", nel senso che serve appunto per leggere un oggetto. Mentre
se vuoi leggere "n byte", secondo il C++ tu stai leggendo appunto "n
byte" , se poi per te rappresentano una stringa lui non lo sa. La
possibilità di leggere una stringa ce l'hai, se vuoi leggere i bytes, è
responsabilità tua convertirli in stringa.

 quella che stai utilizzando.
Capisco cosa intendi, però considera quello che segue.
Ammettiamo che la rappresentazione sia condivisa. Deferenziando begin()
devi trovarti comunque nella condizione di poter modificare a tuo
piacimento il primo carattere della stringa senza interferire con altre
stringhe. Quindi possono darsi tre casi:
   - la chiamata a begin() interrompe la condivisione
   - la dereferenziazione dell'iteratore interrompe la condivisione   
   - la dereferenziazione dell'iteratore restituisce un'oggetto temporaneo
     di una classe proxy che "mima" il comportamento di un char e
     interrompe la condivisione quando gli assegniamo un valore
La terza è un'implementazione poco sensata e comunque non consentirebbe al
nostro codice di compilare, giacché non si può ricavare esplicitamente
l'indirizzo di un oggetto temporaneo.
Max

 Nicola
Ciao, Diego