Как определить, есть ли файл на диске
ОГЛАВЛЕНИЕ
Способ 1 (access)
Библиотечная функция access позволяет определять режим доступа к файлу, а если второй параметр mode равен нулю, то определяется только существование файла.
|  bool FileExists (const char *fname) {return access(fname,0) != -1; } | 
Хотя эта фукция и не входит в стандарт C/C++, тем не менее она присутствует в компиляторах Visual C++, Borland C++, Watcom C++ и многих других в неизменном виде.
 
Способ 2 (_findfirst)
Функция _findfirst возвращает информацию о первом файле, удовлетворяющем заданной маске поиска. Если указать точное имя файла, то мы сможем ответить на наш вопрос.
|  bool FileExists (const char *fname) {    _finddata_t data;    long nFind = _findfirst(fname,&data);if (nFind != -1) { // Если этого не сделать то произойдет утечка ресурсов _findclose(nFind) return true; } return false; } | 
С помощью этого способа можно определять не только существование отдельного файла, но также и группы файлов, соответствующей заданной маске. А если задать маску как "*.*", то можно узнать есть ли файлы в заданной директории.
 
Способ 3 (GetFileAttributes)
Функция GetFileAttributes Win32 API возвращает атрибуты для заданного файла или каталога. В случае ошибки возвращается значение 0xFFFFFFFF.
|  bool FileExists (LPCTSTR fname) {return ::GetFileAttributes(fname) != DWORD(-1); } | 
Этот способ используется во многих примерах из MSDN, что позволяет предположить, что это штатный способ для решения нашей задачи в Win API. Кроме того, это самый быстрый из приведенных здесь способов.
 
Способ 4 (FindFirstFile)
Этот способ аналогичен способу 2 с той лишь разницей, что для достижения результата используется функция Win32 API.
|  bool FileExists (LPCTSTR fname) {    WIN32_FIND_DATA wfd;    HANDLE hFind = ::FindFirstFile(fname, &wfd);if (INVALID_HANDLE_VALUE != hFind) { // Если этого не сделать то произойдет утечка ресурсов ::FindClose(hFind) return true;     }return false; } | 
 
Способ 5 (MFC)
MFC содержит класс-обёртку для функций Find... API. Мы вполне можем использовать этот класс.
|  bool FileExists (LPCTSTR fname) {return CFileFind().FindFile(fname) == TRUE; } | 
 
Способ 6 (WTL)
Среди прочих классов, подобных MFC, WTL также содержит и CFileFind. Следовательно, этот способ внешне ни чем не отличается от предыдущего, кроме того, что не требует MFC.DLL. На самом деле этот способ намного быстрее предыдущего. Дело в том, что все функции класса CFileFind являются inline, так что код, генерируемый компилятором, почти целиком совпадает с кодом для способа 4.
| #include <AtlMisc.h>  bool FileExists (LPCTSTR fname) {return CFileFind().FindFile(fname) == TRUE; } | 
 
Способ 7 (PathFileExists)
Ещё один способ из предложенных Александром Шаргиным - использование SHLWAPI Path API.
| #include <shlwapi.h> #pragma comment(lib,"shlwapi")  bool FileExists (LPCTSTR fname) {return ::PathFileExists(fname) == TRUE; } | 
Правда у этого способа имеются определённые недостатки, которые значительно сужают его практическое применение:
§ Он не будет работать, если на компьютере не установлен Internet Explorer 4.0 или выше, что может быть вполне вероятно на компьютерах с ранними версиями Windows 95 и Window NT 4.0.
§ Функция PathFileExists() не поддерживает UNC имена файлов.
 
Способ 8 (CreateFile)
Самый очевидный и самый громоздкий способ.
|  bool FileExists (LPCTSTR fname) {    HANDLE hFile = ::CreateFile(fname, // file (or device) name 0, // query access only FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, // share mode NULL, // security attributes OPEN_EXISTING, // disposition FILE_FLAG_NO_BUFFERING | FILE_FLAG_SEQUENTIAL_SCAN, // flags & attributes NULL // template file         );        if (INVALID_HANDLE_VALUE != hFile) {         ::CloseHandle(hFile);return true;     } return false; } | 
 
Способ 9 (Pure C++ метод std::ifstream, ::ifstream)
Данный метод состоит в создании временного объекта класса ifstream. Если файл с указанным именем не существует то operator void *() этого класса возвращает NULL pointer - иначе возвращается указатель на сам созданный об'ект (this). Это значение проверяется на NULL pointer - и ... все.
|  bool FileExists (const char *fname) {return std::ifstream(fname) != NULL; } | 
... вернее почти все =)
В данном коде ifstream это typedef basic_ifstream<char, char_traits<char> > ifstream; если же Вы пользуетесь старыми заголовочными файлами (с разширением .h) - то для Вас ifstream - это никакой не typedef - а самый настоящий класс. И все было бы прекрасно - если бы не одно но - в этом случае конструктор с именем файла в качестве параметра СОЗДАСТ файл (если он не существует) и в любом случаем проверка на существование файла даст положительный результат. Дело в том что для "старого" ifstream'а надо явно указывать что НЕ надо создавать файл через добавление флага ios::nocreate во втором параметре конструктора. А вот и сам код для такого случая:
|  bool FileExists (const char *fname) {return ::ifstream(fname, ios::in | ios::nocreate) != NULL; } | 
Данный метод хорош тем что он 100% портабелен - то есть используются только возможности самого языка С++ (в лице его стандартной библиотеки - которая является его частью).
 
Способ 10 (.NET)
Могу вас обрадовать, в .NET все наши мучения закончатся. Для выяснения существования файла можно будет просто вызвать метод FileExists класса File. Например:
|  | 
 
Способ 11 (Script)
Ни один из перечисленных способов не будет работать из .html документа. Зато из скрипта доступен Scripting.FileSystemObject и нам этого достаточно.
| {var fso = new ActiveXObject("Scripting.FileSystemObject"); return fso.FileExists(fname); } | 
Мы вполне можем использовать Scripting.FileSystemObject и в COM-модуле:
| {    CComPtr<IFileSystem> pfs;HRESULT hr = pfs.CoCreateInstance(OLESTR("Scripting.FileSystemObject")); if (SUCCEEDED(hr)) {         VARIANT_BOOL ret = VARIANT_FALSE;        hr = pfs->raw_FileExists(fname, &ret);        if (SUCCEEDED(hr))            hr = ret ? S_OK : S_FALSE;} return hr; } | 
Фактически, это очень извращенный способ вызова все той же функции access() из способа 1, с той разницей, что FileSystemObject работает с именами файлов в UNICODE и под WindowsNT/2k передает имя файла напрямую, а под Windows 9x/Me (и даже 3.1 с интернет эксплорером!) сам преобразовавает его в ANSI.
