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ć?


<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;
}

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


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ć.


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.


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
}

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();
}

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ć?


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;
}

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 .


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);
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.