Programowanie w języku C/C++ » FAQ

Jak sprawdzić, czy dany plik istnieje

  • 1 komentarz
  • 8186 odsłon
  • Oceń ten tekst jako pierwszy
Wbrew pozorom, sposobów na rozwiązanie tego banalnego problemu jest wiele, mimo, że język C/C++ sam w sobie nie oferuje żadnej standardowej funkcji, która sprawdzałaby istnienie danego pliku. By znaleźć rozwiązanie trzeba więc nieco pokombinować, ale z pewnością się to opłaci, bo dzięki zastosowaniu jakieś uniwersalnej metody, nasz kod nie będzie zależny tylko i wyłącznie od danej platformy. Reasumując, warto przyjrzeć się najczęściej spotykanym metodom.

Sposoby uniwersalne


Chwilami dość alternatywne, ale działają bez problemu na niemal każdej platformie. Rekomendowane wszędzie tam, gdzie na uwadze jest uniwersalność kodu.

Strumienie


<justify>     Z pewnością najwolniejszy z możliwych i niezalecany, a jednak dziwnym trafem najczęściej wybierany z uwagi na uniwersalność. Działa identycznie, niezależnie od platformy. Polega na zwykłej próbie odczytu pliku, a następnie sprawdzeniu, czy uzyskany został wskaźnik do pliku. Powodzenie tej akcji jest równoznaczne z tym, że dany plik istnieje. Uwaga! Przy tej metodzie należy uważać na tryb otwierania pliku. Ustawienie trybu np. na dopisywanie spowoduje, że jeśli otwierany plik nie istnieje, wówczas zostanie utworzony, a przecież nie o to chodzi (→zobacz fopen)</justify>
#include <fstream>
using namespace std;
 
bool fileExists (const string& fileName)
{
        fstream plik;
        plik.open(fileName.c_str(), ios::in | ios::nocreate);  /* ważne, by nie tworzyć pliku, jeśli nie istnieje, stąd flaga nocreate */
        if ( plik.is_open() )
        {
            plik.close();
            return true;
        }
        plik.close();
        return false;
}
 
int main (void)
{
        if ( fileExists("dane.txt") )
           cout<<"Plik istnieje"<< endl;
        else
           cout<<"Plik nie istnieje"<< endl;
        return 0;
}

#include <stdio.h>
#include <stdlib.h>
 
int fileExists (const char* fileName)
{
        FILE* plik;
        plik = fopen(fileName, "r");  /* ważne, by nie tworzyć pliku, jeśli nie istnieje, tryb "r" (tylko odczyt) */
        if ( plik )
        {
            fclose(plik);
            return 1;
        }
        fclose(plik);
        return 0;
}
 
int main (int argc, char* argv[])
{
        if ( fileExists("dane.txt") )
           printf("Plik istnieje\n");
        else
           printf("Plik nie istnieje\n");
        return 0;
}

Statystyki


<justify>     Dużo lepszą i przede wszystkim także uniwersalną metodą jest odczytanie statystyk pliku. Statystyki przechowują takie informacje, jak data utworzenia i ostatniej modyfikacji pliku, jego prawa dostępu, rozmiar w bajtach i wiele innych. Oczywiście w zależności od systemu plików, tych danych jest mniej lub więcej. Jedno jest pewne: jeżeli plik nie istnieje, nie można odczytać jego statystyk. I ten właśnie fakt został wykorzystany w poniższej metodzie. Powodzenie przy odczytaniu statystyk równoznaczne jest z tym, że plik istnieje. Uwaga! W zależności od implementacji, funkcja stat() (albo _stat() lub _fstat()) może pobierać różne argumenty. Warto wówczas zaznajomić się z zawartością <sys/stat.h>.</justify>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
 
int fileExists (const char* fileName)
{
        struct stat buf;
        /* Odczytywanie statystyk pliku */
        if ( stat(fileName, &buf) == 0 )
            return 1;
        else
            return 0;
}
 
int main (int argc, char* argv[])
{
        if ( fileExists("dane.txt") )
            printf("Plik istnieje!\n");
        else
            printf("Plik nie istnieje!\n");
        return 0;
}

Funkcja access() [UNIX/Win32]


<justify>     Jedna z najlepszych metod ze względu na uniwersalność oraz prostotę. Polega na sprawdzeniu dostępu do pliku za pomocą funkcji access(), wchodzącej w skład biblioteki standardowej <unistd.h> (w przypadku UNIX'a) albo <io.h> (w przypadku Win32). Żeby zwiększyć przenośność kodu do maksimum (oraz, żeby w zależności od platformy, używać odpowiedniej biblioteki) zastosowano odpowiednie dyrektywy preprocesora.</justify>
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
#include <io.h>
#else
#include <unistd.h>
#endif
 
 
int fileExists (const char* fileName)
{
        /* Sprawdzenie dostępu do pliku (jeżeli takowy istnieje, musi istnieć plik) */
        #ifdef WIN32
        return !access(fileName, 0);    /* w przypadku Win32 */
        #else
        return !access(fileName, F_OK);    /* w przypadku UNIX'a */
        #endif
}
 
int main (int argc, char* argv[])
{
        if ( fileExists("dane.txt") )
            printf("Plik istnieje!\n");
        else
            printf("Plik nie istnieje!\n");
        return 0;
}


Semantyka funkcji access() w systemie Linux nie jest tak prosta jakby się mogło wydawać. Otóż funkcja ta zwraca tylko prawa przysługujące uprawnieniom real, nie zaś effective - tak więc ma pewne zastosowanie w programach używających praw setuid czy też setgid. Naiwne stosowanie - sprawdzenie za pomocą wywołania access, po czym otwarcie pliku za pomocą open - stwarza jednak lukę czasową, w trakcie której plik może zostać podmieniony.

Biblioteka standardowa [C++ Builder]


<justify>     C++ Builder posiada wbudowaną funkcję, która sprawdza, czy dany plik istnieje.</justify>
#include <SysUtils.hpp>
#include <Dialogs.hpp>
 
        if ( FileExists("dane.txt") == true )
            ShowMessage("Plik istnieje");
        else
            ShowMessage("Plik nie istnieje");


Zależne od platformy


Sprawdzone i w pełni działające metody pod określone platformy.

Win API


<justify>     Metoda podobna do tej z wykorzystaniem struktur, jednak bez wątpienia wygodniejsza. Za jej pomocą można także bez problemu sprawdzić, czy istnieje katalog o danej nazwie.</justify>
#include <windows>
using namespace std;
 
bool fileExists (const char* fileName)
{
        DWORD attrib;
        attrib = GetFileAttributes(fileName);
        return ( attrib == ((DWORD)-1) )
}
 
int main (void)
{
        if ( fileExists("dane.txt") )
            cout<<"Plik istnieje!"<<endl;
        else
            cout<<"Plik nie istnieje!"<<endl;
        return 0;
}

Biblioteka niestandardowa Shlwapi.h [Win32]


<justify>     Wykorzystanie bardzo wygodnej w użyciu funkcji sprawdzającej, czy dany plik istnieje. Sama biblioteka jest godna uwagi ze wzgledu na dużą ilość funkcji operujących na plikach. Uwaga! Funkcja nie chce współpracować ze stałymi znakowymi, dlatego bezpieczniej jako argument podać wskaźnik na istniejący łańcuch.</justify>
#include <windows.h>
#include <iostream.h>
#include "Shlwapi.h"
 
int main (int argc, char* argv[])
{
        static char buffer[ ] = "C:\\dane.txt"; 
        char *lpStr;
        lpStr = buffer;
 
        if ( PathFileExists(lpStr) )
            printf("Plik istnieje!\n");
        else
            printf("Plik nie istnieje!\n");
        return 0;
}

1 komentarz

Ranczer 2010-02-08 20:18

  1. include <iostream>
  2. include <fstream>
using namespace std;
bool file_exists( const char *cSpecyf_Zbioru )
{
  ifstream zbior( cSpecyf_Zbioru );
  return zbior;
}

int main()
{
  if ( file_exists( "a.cpp") )
  {
    cout << "Zbior istnieje";
  }
  else
  {
    cout << "Zbior nie istnieje";
  }
  return 0;
}
/*----------
Zwracane wartości
file_exists() zwraca prawdę true, czyli 1, jeżeli istnieje odpowiedni "cSpecyf_Zbioru"; w przeciwnym przypadku zwraca false, czyli 0
Pozdrawiam ;-)
----------*/