Библиотечная функция access позволяет определять режим доступа к файлу, а если второй параметр mode равен нулю, то определяется только существование файла.
#include <io.h> bool FileExists(const char *fname) { returnaccess(fname, 0) != -1; } |
Хотя эта функция и не входит в стандарт C/C++, тем не менее, она присутствует в компиляторах Visual C++, Borland C++, Watcom C++ и многих других в неизменном виде.
Функция _findfirst возвращает информацию о первом файле, удовлетворяющем заданной маске поиска. Если указать точное имя файла, то мы сможем ответить на наш вопрос.
#include <io.h> bool FileExists (const char *fname) { _finddata_t data; long nFind = _findfirst(fname,&data); if (nFind != -1) { // Если этого не сделать, то произойдет утечка ресурсов _findclose(nFind); return true; } return false; } |
С помощью этого способа можно определять не только существование отдельного файла, но также и группы файлов, соответствующей заданной маске. А если задать маску как "*.*", то можно узнать есть ли файлы в заданной директории.
Функция GetFileAttributes Win32 API возвращает атрибуты для заданного файла или каталога. В случае ошибки возвращается значение 0xFFFFFFFF.
#include <windows.h> bool FileExists(LPCTSTR fname) { return::GetFileAttributes(fname) != DWORD(-1); } |
Этот способ используется во многих примерах из MSDN, что позволяет предположить, что это штатный способ для решения нашей задачи в Win API. Кроме того, это самый быстрый из приведенных здесь способов.
Этот способ аналогичен способу 2 с той лишь разницей, что для достижения результата используется функция Win32 API.
#include <windows.h> bool FileExists(LPCTSTR fname) { WIN32_FIND_DATA wfd; HANDLE hFind = ::FindFirstFile(fname, &wfd); if (INVALID_HANDLE_VALUE != hFind) { // Если этого не сделать то произойдет утечка ресурсов ::FindClose(hFind); return true; } return false; } |
MFC содержит класс-обёртку для функций Find... API. Мы вполне можем использовать этот класс.
#include <afx.h> bool FileExists(LPCTSTR fname) { returnCFileFind().FindFile(fname) == TRUE; } |
Среди прочих классов, подобных MFC, WTL также содержит и CFileFind .Следовательно, этот способ внешне ни чем не отличается от предыдущего, кроме того, что не требует MFC.DLL. На самом деле этот способ намного быстрее предыдущего. Дело в том, что все функции класса CFileFind являются inline,так что код, генерируемый компилятором, почти целиком совпадает с кодом для способа 4.
#define _WTL_NO_CSTRING // только для любителей "чистого" API#include <AtlMisc.h> bool FileExists(LPCTSTR fname) { returnCFileFind().FindFile(fname) == TRUE; } |
Ещё один способ из предложенных Александром Шаргиным - использование SHLWAPI Path API .
#include <windows.h> #include <shlwapi.h> #pragma comment(lib, "shlwapi") bool FileExists(LPCTSTR fname) { return::PathFileExists(fname) == TRUE; } |
Правда у этого способа имеются определённые недостатки, которые значительно сужают его практическое применение:
Самый очевидный и самый громоздкий способ.
#include<windows.h> bool FileExists(LPCTSTR fname) { HANDLE hFile = ::CreateFile( fname, // file (or device) name0, // 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; } |
Данный метод состоит в создании временного объекта класса ifstream .Если файл с указанным именем не существует то operator void*() этого класса возвращает NULL pointer - иначе возвращается указатель на сам созданный объект (this). Это значение проверяется на NULL pointer - и ... все.
#include <fstream> bool FileExists(const char *fname) { returnstd::ifstream(fname) != NULL; } |
... вернее почти все =)
В данном коде ifstream это typedef basic_ifstream < char, char_traits <char>> ifstream; если же Вы пользуетесь старыми заголовочными файлами (с расширением .h) - то для Вас ifstream - это никакой неtypedef- а самый настоящий класс. И все было бы прекрасно - если бы не одно но - в этом случае конструктор с именем файла в качестве параметра СОЗДАСТ файл (если он не существует) и в любом случае, проверка на существование файла даст положительный результат. Дело в том, что для "старого" ifstream 'а надо явно указывать что НЕ надо создавать файл через добавление флага ios::nocreate во втором параметре конструктора. А вот и сам код для такого случая:
#include <fstream.h> bool FileExists(const char *fname) { return ::ifstream(fname, ios::in | ios::nocreate) != NULL; } |
Данный метод хорош тем что он 100% портабелен - то есть используются только возможности самого языка С++ (в лице его стандартной библиотеки - которая является его частью).
Могу вас обрадовать, в .NET все наши мучения закончатся. Для выяснения существования файла можно будет просто вызвать метод FileExists класса File . Например:
System.IO.File.FileExists("c:\\autoexec.bat"); |
Ни один из перечисленных способов не будет работать из .html документа. Зато из скрипта доступен Scripting.FileSystemObject и нам этого достаточно.
function FileExists(fname) { var fso = new ActiveXObject("Scripting.FileSystemObject"); returnfso.FileExists (fname); } |
Мы вполне можем использовать Scripting.FileSystemObject и в COM-модуле:
HRESULT FileExists(LPOLESTR oszFilename) { 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.