Как определить, есть ли файл на диске
ОГЛАВЛЕНИЕ
Способ 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.