Jaki jest najlepszy sposób sprawdzenia, czy plik istnieje w C ++? (między platformami)

97

Przeczytałem odpowiedzi na temat Jak najlepiej sprawdzić, czy plik istnieje w C? (wiele platform) , ale zastanawiam się, czy istnieje lepszy sposób na zrobienie tego przy użyciu standardowych bibliotek C ++? Najlepiej bez próby otwarcia pliku.

Obydwa stati accesssą prawie niemożliwe do usunięcia. Czego mam #includeich używać?

c0m4
źródło
<io.h> w celu uzyskania dostępu (w rzeczywistości może to być _access).
Rob
Tak, jak wskazano stąd.
c0m4

Odpowiedzi:

170

Użyj boost :: filesystem :

#include <boost/filesystem.hpp>

if ( !boost::filesystem::exists( "myfile.txt" ) )
{
  std::cout << "Can't find my file!" << std::endl;
}
Andreas Magnusson
źródło
68
Wydaje się, że to trochę mgliste, aby zainstalować ogromną bibliotekę innej firmy, aby zrobić coś, co powinno być proste
c0m4
89
Boost to biblioteka, w której opracowywanych jest wiele elementów, które ostatecznie staną się częścią standardowej biblioteki C ++. Wiele osób zaangażowanych w boost to osoby związane ze standardem C ++. Więc impuls nie tylko każdy biblioteki strona trzecia. Jeśli programujesz w C ++, powinieneś mieć zainstalowany boost!
Andreas Magnusson
Wydaje mi się, że b :: fs :: exist zwraca „true” na nieistniejących plikach w udziałach sieciowych: „\\ machine \ share \ this_file_doesnt_exist” => true. Ostatni raz sprawdzałem było na
boostie
Jeśli Twój kompilator ma implementację tr1, nie musisz nawet instalować Boost. Będzie w std :: tr1 :: filesystem
Nemanja Trifunovic
1
Właściwie ASFAIK nie stworzył TR1, ale zostanie dodany w późniejszym etapie. Nie znalazłem również żadnych odniesień do tego w oficjalnym szkicu TR1: open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf
Andreas Magnusson
41

Uważaj na warunki wyścigu: jeśli plik zniknie między sprawdzeniem „istnieje” a momentem jego otwarcia, program nieoczekiwanie zakończy się niepowodzeniem.

Lepiej jest iść i otworzyć plik, sprawdzić, czy nie ma awarii i jeśli wszystko jest w porządku, zrób coś z plikiem. Jest to jeszcze ważniejsze w przypadku kodu krytycznego dla bezpieczeństwa.

Szczegóły dotyczące bezpieczeństwa i warunków wyścigu: http://www.ibm.com/developerworks/library/l-sprace.html

rlerallut
źródło
30

Jestem szczęśliwym użytkownikiem doładowania i na pewno skorzystałbym z rozwiązania Andreasa. Ale jeśli nie masz dostępu do bibliotek boost, możesz użyć biblioteki strumieniowej:

ifstream file(argv[1]);
if (!file)
{
    // Can't open file
}

To nie jest tak przyjemne, jak boost :: filesystem :: istnieje, ponieważ plik zostanie faktycznie otwarty ... ale to zwykle jest następna rzecz, którą chcesz zrobić.

MattyT
źródło
15
Ale z tym kodem możesz również wskoczyć do klauzuli if, jeśli nie masz uprawnień do pliku, chociaż istnieje. W większości przypadków nie ma to znaczenia, ale nadal warto o tym wspomnieć.
scigor
1
Zauważyłem, że good () również daje wartość true, jeśli podany argument wskazuje katalog, patrz stackoverflow.com/questions/9591036/ ...
FelixJongleur42.
12

Użyj stat (), jeśli jest wystarczająco wieloplatformowy dla twoich potrzeb. Nie jest to jednak standard C ++, ale POSIX.

W MS Windows jest _stat, _stat64, _stati64, _wstat, _wstat64, _wstati64.

activout.se
źródło
1
<sys / types.h> i <sys / stat.h> Zobacz msdn.microsoft.com/en-us/library/14h5k7ff(VS.71).aspx
activout.se
1
Dobra odpowiedź +1 za NIE UŻYWANIE BOOSTA , ponieważ jest to przesada, jednak nie było trywialne napisanie tego z tego, co tutaj podano, więc właśnie opublikowałem odpowiedź. Sprawdź to proszę.
gsamaras
9

A co powiesz access?

#include <io.h>

if (_access(filename, 0) == -1)
{
    // File does not exist
}
Obrabować
źródło
Czy io.h jest normalnie dostępny w systemie Windows i Linux, nawet jeśli nie jest standardem?
c0m4
1
access () to funkcja POSIX, która jest dostępna poprzez <unistd.h> w Linuksie.
Alex B
9

Inna możliwość polega na wykorzystaniu good()funkcji w strumieniu:

#include <fstream>     
bool checkExistence(const char* filename)
{
     ifstream Infield(filename);
     return Infield.good();
}
Samer
źródło
7

Zastanowiłbym się ponownie, próbując dowiedzieć się, czy plik istnieje. Zamiast tego powinieneś spróbować otworzyć go (w Standard C lub C ++) w tym samym trybie, w którym zamierzasz go używać. Jaki pożytek to wiedzieć, że plik istnieje, jeśli, powiedzmy, nie można go zapisać, kiedy trzeba go użyć?

fizzer
źródło
A co jeśli piszesz lspodobny program? Domyślam się, że oryginalny plakat w ogóle nie chce otwierać pliku. Funkcja stat Posix ma jednak dostarczać informacji o uprawnieniach do pliku, więc rozwiązałaby ten problem.
Michael
6

Jeśli Twój kompilator obsługuje C ++ 17, nie potrzebujesz przyspieszenia, możesz po prostu użyć std::filesystem::exists

#include <iostream> // only for std::cout
#include <filesystem>

if (!std::filesystem::exists("myfile.txt"))
{
    std::cout << "File not found!" << std::endl;
}
AlbertM
źródło
3

NIE WYMAGANE , co byłoby przesadą .


Użyj stat () (nie cross platform, jak wspomniano w pavon), na przykład:

#include <sys/stat.h>
#include <iostream>

// true if file exists
bool fileExists(const std::string& file) {
    struct stat buf;
    return (stat(file.c_str(), &buf) == 0);
}

int main() {
    if(!fileExists("test.txt")) {
        std::cerr << "test.txt doesn't exist, exiting...\n";
        return -1;
    }
    return 0;
}

Wynik:

C02QT2UBFVH6-lm:~ gsamaras$ ls test.txt
ls: test.txt: No such file or directory
C02QT2UBFVH6-lm:~ gsamaras$ g++ -Wall main.cpp
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out
test.txt doesn't exist, exiting...

Kolejną wersję (i tę) można znaleźć tutaj .

gsamaras
źródło
Nie przeciwnik, ale pytanie dotyczyło rozwiązania wieloplatformowego, a statystyka nie istnieje na wszystkich platformach.
pavon
0

Jeśli używasz już klasy stream pliku wejściowego ( ifstream), możesz użyć jej funkcji fail().

Przykład:

ifstream myFile;

myFile.open("file.txt");

// Check for errors
if (myFile.fail()) {
    cerr << "Error: File could not be found";
    exit(1);
}
Reza Saadati
źródło