2011-09-16 2 views
9

Come mio apprendimento, sto cercando di utilizzare C++ ifstream e il relativo operatore >> per leggere i dati da un file di testo utilizzando il codice seguente. Il file di testo outdummy.txt ha seguente contenuto:Utilizzo dell'operatore di estrazione ifstream C++ >> per leggere i dati formattati da un file

just dummy 
Hello ofstream 
555 

Le mie domande è come leggere i dati char presenti nel file in un array di caratteri o una stringa. Come fare ciò usando l'operatore ifstream :: >> nel codice qui sotto.

#include <iostream> 
#include <fstream> 

int main() 
{ 
    int a; 
    string s; 
    char buf[100]; 
    ifstream in("outdummy.txt",ios_base::in); 


    in.operator>>(a); //How to read integer? How to read the string data.?? 

    cout << a; 

    in.close(); 
    getchar(); 
    return 0; 
} 
+2

Il tuo esempio è sbagliato; non si legge nemmeno "l'intero correttamente". In effetti, quella riga fallisce e 'a' è invariato, ma per qualche motivo l'hai già inizializzato al valore atteso, quindi ti sei bendato. –

+0

@Kerrek ha ragione. Ed è [fornito] (http://stackoverflow.com/questions/7443787/using-c-ifstream-extraction-operator-to-read-formatted-data-from-a-file/7443877#7443877) il corretto e facile -to-use solution - il 'getline' con' string'. –

+1

Perché 'char []'? Perché non 'std :: string'? –

risposta

14

Se si desidera utilizzare il metodo formattato, dovete sapere in anticipo quali dati si aspettano e leggerlo in variabili del tipo di dati secondo. Ad esempio, se si sa che il numero è sempre il quinto motivo, come nel tuo esempio, si potrebbe fare questo:

std::string s1, s2, s3, s4; 
int n; 

std::ifstream in("outdummy.txt"); 

if (in >> s1 >> s2 >> s3 >> s4 >> n) 
{ 
    std::cout << "We read the number " << n << std::endl; 
} 

D'altra parte, se si sa che il numero è sempre in terza linea, di per sé:

std::string line; 

std::getline(in, line); // have line 1 
std::getline(in, line); // have line 2 
std::getline(in, line); // have line 3 

std::istringstream iss(line); 

if (iss >> n) 
{ 
    std::cout << "We read the number " << n << std::endl; 
} 

come si può vedere, a leggere un token come una stringa, è sufficiente streaming in una std::string. È importante ricordare che l'operatore di input formattato lavora token per token, e i token sono separati da spazi bianchi (spazi, tabulazioni, newline). La solita scelta fondamentale da fare è se si elabora un file interamente in token (prima versione) o riga per riga (seconda versione). Per l'elaborazione riga per riga, utilizzare prima getline per leggere una riga in una stringa e quindi utilizzare un flusso di stringa per tokenizzare la stringa.


Una parola sulla convalida: non è possibile sapere se l'estrazione di un formattata sarà effettivamente successo, perché questo dipende dai dati di input. Pertanto, è necessario sempre controllare se un'operazione di input è riuscita e abortire l'analisi in caso contrario, perché in caso di errore le variabili non conterranno i dati corretti, ma non si avrà modo di saperlo successivamente. Quindi, sempre dire così:

if (in >> v) { /* ... */ }   // v is some suitable variable 
else { /* could not read into v */ } 

if (std::getline(in, line)) { /* process line */ } 
else { /* error, no line! */ } 

Quest'ultima costruzione di solito è usato in un ciclo while, a leggere un intero file riga per riga:

while (std::getline(in, line)) { /* process line */ } 
+0

Grazie per la risposta dettagliata. – goldenmean

2
  1. ifstream ha ios_base::in per impostazione predefinita. Non è necessario specificarlo.
  2. operator>> può essere richiamato direttamente come operatore: in >> a.
  3. Le stringhe di lettura sono le stesse: in >> s, ma l'avvertenza è che è delimitata da spazi bianchi, quindi leggerà "solo" da sola, senza "dummy".
  4. Se si desidera leggere le righe complete, utilizzare std::getline(in, s).
1

Dal momento che si è scelto di utilizzare C-stringhe, è possibile utilizzare il metodo getline del ifstream oggetto (non std::getline() che funziona con std::string s), che vi permetterà di specificare il C-string e una dimensione massima per il buffer.

In base a quello che aveva, e l'aggiunta di un buffer aggiuntivo per la seconda linea:

char buf[100]; 
char buf2[100]; 

in.getline(buf,sizeof(buf)); 
in.getline(buf2,sizeof(buf2)); 
in >> a; 

Tuttavia, come l'altro poster ha proposto, provare a utilizzare il std::string e dei suoi metodi, che renderà la vita più facile .

+1

Ewwww. C array. Numeri magici :-( –

+0

@Kerrek Predica al coro, ma sto cercando di adattarlo al suo esempio – jonsca

+0

abbastanza giusto, ma penso che se qualcuno suggerisce "in.operator >> (a)" in primo luogo, è tempo per un cambio di vestiti :-) –

0

È possibile leggere il contenuto del file e utilizzare un Finite State Machine per l'analisi.

Esempio:

void Parse(const char* buffer, size_t length); 
size_t GetBufferSize(); 

size_t bufferSize = GetBufferSize(); 
char* buffer = new char[bufferSize]; 

std::ifstream in("input.txt"); 
while(in.getline(buffer, bufferSize)) { 
    Parse(buffer, in.gcount()); 
} 

In alternativa, è possibile utilizzare uno strumento come Flex per scrivere il parser.

+0

Allocazione dinamica di un array di caratteri? Sul serio? Qualcosa non va con 'std :: string'? –

+0

Ho usato un array di caratteri allocato dinamicamente per essere coerente con l'esempio incluso nella domanda. Naturalmente sarebbe più appropriato usare un contenitore come 'string',' rope' o 'vector ' invece di un array di caratteri nel codice di produzione e dovrei averlo menzionato. – npclaudiu

+0

La domanda non ha allocato dinamicamente una matrice 'char'. –