2012-03-06 14 views
7

In un programma C++, usando std :: ifstream, sto tentando di aprire un file specificato dall'utente - finora così buono. Tuttavia, ho accidentalmente inserito un nome di file che è in realtà una directory, e sono rimasto piuttosto sorpreso nel vedere che il tentativo di aprire() quella directory non ha generato alcun errore.Ifstream open() non imposta i bit di errore quando argomento è una directory

Ecco un esempio minimo:

std::ifstream f; 
f.open(".."); 
if(!f.is_open() || !f.good() || f.bad() || f.fail()) { 
    std::cout << "error bit set on open" << std::endl; 
    return 1; 
} 

Nessun segno di un errore qui. Se continuo a tentare di getline(), getline() imposta un bit di errore.

std::string str; 
getline(f, str); 

if(f.eof()) std::cout << "getline set eofbit" << std::endl; 
else if(f.bad()) std::cout << "getline set badbit" << std::endl; 
else if(f.fail()) std::cout << "getline set failbit" << std::endl; 

Questo output "setline set badbit", che è ragionevole. L'utilizzo dell'operatore >> genera un'eccezione di underflow, anch'essa accettabile.

Ora, la mia domanda è, come posso rilevare che l'utente ha inserito un nome di directory invece di un nome file corretto? C'è un modo per farlo? Ottenere e annullare i byte dal flusso sembrano noiosi e soggetti a errori.

Inoltre, perché è così? Mi rendo conto che sono tutti gli stessi dati dal punto di vista del programma, ma suppongo che il sistema operativo invii anche un messaggio di tipo "hey, this is a directory".

+0

Su quale piattaforma stai ottenendo questo comportamento? –

+0

C++ non ha la nozione di "directory". È necessaria una libreria specifica per piattaforma (come Posix o Windows). –

+0

Oh, Ubuntu 10.04, il compilatore è gcc 4.4.3. –

risposta

3

Tu non dici quello che il vostro sistema è, quindi è difficile da dire, ma in generale, filebuf::open restituirà solo un errore se il vostro livello di sistema aperto fallisce. E ho lavorato su sistemi Unix in cui è possibile open() una directory ; Ho persino lavorato su alcuni in cui è possibile leggerlo dopo lo aperto (almeno se si trattava di un filesystem montato localmente).

Per quanto riguarda cosa fare al riguardo: tutto quello che posso pensare è provare il get il primo carattere, quindi rimetterlo. Ma questo fallisce se il file è vuoto, quindi non è nemmeno una soluzione. A livello di sistema (e da un punto di vista QoI, mi aspetterei che filebuf::open esegua questa operazione se il sistema consentiva l'apertura di una directory), è possibile utilizzare una chiamata a livello di sistema (stat in Unix) per determinare se il il file è una directory o no. (C'è una condizione di gara, ovviamente: tra il momento in cui si rileva che è un file normale, e nel momento in cui si apre, un altro processo potrebbe eliminare il file e creare una directory. Probabilmente non è un caso frequente , tuttavia.)

+0

Oh, quindi è specifico per la piattaforma, dopotutto, avrei potuto indovinare. Grazie per la spiegazione. Sì, questo è su Linux (Ubuntu, lo stesso accade su Debian, non sorprendentemente). Dal momento che sto solo cercando di assicurarmi che sia un filestream valido e leggibile da cui posso leggere le cose, ottenere e non accettare è ragionevole, anche se speravo in una soluzione più pulita. Le dipendenze e le chiamate di sistema sembrano eccessive. Voglio dire, posso vivere con l'errore, ma, ehm, sembrava solo strano. –

+1

@ SáT: Direi anche che è specifico del file system sottostante utilizzato sull'hardware (nota: alcuni sistemi operativi consentono di scegliere il filesystem utilizzato sui dischi). –

+1

@LokiAstari Penso di sì. IIRC (è passato un po 'di tempo da quando l'ho provato), in Solaris, 'open' su una directory funzionava su dischi localmente installati (UFS), ma non se il filesystem era NFS. –

Problemi correlati