2013-07-23 13 views
25

Voglio inserire alcuni contenuti in un file, ma vorrei verificare prima se esiste un file con il nome che desidero creare. Se è così, non voglio creare alcun file, anche se il file è vuoto.Come verificare se esiste un file prima di creare un nuovo file

Il mio tentativo

bool CreateFile(char name[], char content[]){ 
    std::ofstream file(name); 
    if(file){ 
     std::cout << "This account already exists" << std::endl; 
     return false; 
    } 
    file << content; 
    file.close(); 
    return true; 
} 

Esiste un modo per fare quello che voglio?

+4

... cercare di aprirlo e leggerlo prima? –

+1

secondo modo è controllarlo percorso se esiste 'fstat()'. –

+1

So che Windows consente di gestirlo come un'operazione atomica in 'CreateFile'. Mi aspetto che altri sistemi comuni abbiano un comportamento equivalente. Sicuramente c'è un'astrazione disponibile nella libreria standard C++? –

risposta

25

Supponendo che è OK che l'operazione non è atomica, si può fare:

if (std::ifstream(name)) 
{ 
    std::cout << "File already exists" << std::endl; 
    return false; 
} 
std::ofstream file(name); 
if (!file) 
{ 
    std::cout << "File could not be created" << std::endl; 
    return false; 
} 
... 

Si noti che questo non funziona se si esegue più thread cercando di creare lo stesso file, e certamente non impedirà un secondo processo da "interferire" con la creazione del file perché si hanno problemi TOCTUI. [Verifichiamo innanzitutto se il file esiste e quindi lo creiamo, ma qualcun altro potrebbe averlo creato tra il controllo e la creazione: se ciò è fondamentale, dovrai fare qualcos'altro, che non è portatile].

Un ulteriore problema è che se si dispone di autorizzazioni come il file non è leggibile (quindi non è possibile aprirlo per la lettura) ma è scrivibile, sovrascriverà il file.

Nella maggior parte dei casi, nessuna di queste cose è importante, perché tutto quello che ti interessa è dire a qualcuno che "hai già un file del genere" (o qualcosa del genere) con un approccio "best effort".

+0

Non funziona (sempre), anche senza condizioni di gara. Se il file ha il permesso di scrittura ma non ha i permessi di lettura, il tuo esempio lo sovrascriverà. – rabensky

+1

@MatsPetersson, FYI - questa condizione di competizione è discussa abbastanza ampiamente in "Secure Coding in C e C++" (Robert Seacord) 2a edizione, capitolo 8, sezione 5. –

+0

@NathanErnst: È un problema abbastanza noto. Ma è solo un problema quando si ha a che fare con file che hanno direttamente aspetti di sicurezza ("/ etc/passwd" o cose simili), o l'applicazione in quanto tale ha aspetti di sicurezza. Per la maggior parte delle applicazioni, provare ad aprire per leggere l'apertura per la scrittura è sufficiente, perché non c'è nulla in competizione per lo stesso nome di file in ogni caso - è solo un promemoria che "hai già usato quel nome, sceglierne un altro". –

7

Prova

ifstream my_file("test.txt"); 
if (my_file) 
{ 
// do stuff 
} 

Da: How to check if a file exists and is readable in C++?

Oppure si potrebbe usare le funzioni di boost.

+1

Questo potrebbe non funzionare se non hai i permessi di lettura per quel file. Naturalmente, la maggior parte dei casi non sarà in grado di scriverlo comunque, ma ci sono alcuni sistemi con permessi strani, e potresti avere permessi di scrittura senza permessi di lettura, distruggendo così il tuo file. – rabensky

13

puoi anche utilizzare Boost.

boost::filesystem::exists(filename); 

funziona per file e cartelle.

E si avrà un'implementazione simile a qualcosa di pronto per C++ 14 in cui il filesystem dovrebbe far parte dell'STL (vedere here).

+0

Miglior risposta finora + 1 per essere multipiattaforma –

3

Guardato intorno un po ', e l'unica cosa che trovo sta usando la chiamata di sistema open. E 'l'unica funzione che ho trovato che consente di creare un file in un modo che non riuscirà se esiste già

#include <fcntl.h> 
#include <errno.h> 

int f=open(filename, O_WRONLY | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); 
if (f < 0) { 
    /* file exists or otherwise uncreatable 
    you might want to check errno*/ 
}else { 
    /* File is open to writing */ 
} 

Nota che devi dare i permessi in quanto si sta creando un file.

Ciò elimina anche eventuali condizioni di gara non ci potrebbero essere

+1

Ovviamente, ora si ha il problema che non si può usare il file come 'fstream', e questo funziona solo su un SO in stile Unix. –

+1

Bene, ora che lo hai creato puoi sempre chiuderlo e riaprirlo (lo "possiedi" ora - sei sicuro di averlo creato). Per quanto riguarda la cosa unix, non lo sapevo! Non ho mai programmato su Windows. Ma google ha trovato la funzione 'CreateFile' in msdn, che dato il flag' CREATE_NEW' fallirà se il file esiste. Quindi immagino che potresti farlo con un '# define' per diversi SO ... Ci dovrebbe essere davvero un modo standard per farlo <. < – rabensky

6

Prova questa (copiato-ish da Erik Garrison: https://stackoverflow.com/a/3071528/575530)

#include <sys/stat.h> 

bool FileExists(char* filename) 
{ 
    struct stat fileInfo; 
    return stat(filename, &fileInfo) == 0; 
} 

stat rendimenti 0 se il file esiste e se non -1.

+0

Non è solo per Linux (POSIX)? Funzionerà anche nell'installazione standard MinGW? – Youda008

0

Ho appena visto questo test:

bool getFileExists(const TCHAR *file) 
{ 
    return (GetFileAttributes(file) != 0xFFFFFFFF); 
} 
0

Il modo più semplice per farlo è usare ios :: noreplace.

+0

Non c'è niente del genere. – BarbaraKwarc

3

partire dal C++ 17 c'è:

if (std::filesystem::exists(pathname)) { 
    ... 
+2

Ci sono voluti solo 19 anni ... xD –

Problemi correlati