Подтвердить что ты не робот

Проверить размер файла, не открывая файл в C++?

Я пытаюсь получить размер файла большого файла (12gb +), и я не хочу открывать файл, чтобы сделать это, поскольку я предполагаю, что это будет много ресурсов. Есть ли хороший API для этого? Я в среде Windows.

4b9b3361

Ответ 1

Вам следует позвонить GetFileSizeEx, который проще в использовании, чем предыдущий GetFileSize. Вам нужно будет открыть файл, вызвав CreateFile, но это дешевая операция. Ваше предположение, что открытие файла дорого, даже 12-гигабайтный файл, является ложным.

Чтобы выполнить задание, вы можете использовать следующую функцию:

__int64 FileSize(const wchar_t* name)
{
    HANDLE hFile = CreateFile(name, GENERIC_READ, 
        FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 
        FILE_ATTRIBUTE_NORMAL, NULL);
    if (hFile==INVALID_HANDLE_VALUE)
        return -1; // error condition, could call GetLastError to find out more

    LARGE_INTEGER size;
    if (!GetFileSizeEx(hFile, &size))
    {
        CloseHandle(hFile);
        return -1; // error condition, could call GetLastError to find out more
    }

    CloseHandle(hFile);
    return size.QuadPart;
}

Существуют другие вызовы API, которые возвратят вам размер файла, не заставляя вас создавать дескриптор файла, в частности GetFileAttributesEx. Однако совершенно правдоподобно, что эта функция просто откроет файл за кулисами.

__int64 FileSize(const wchar_t* name)
{
    WIN32_FILE_ATTRIBUTE_DATA fad;
    if (!GetFileAttributesEx(name, GetFileExInfoStandard, &fad))
        return -1; // error condition, could call GetLastError to find out more
    LARGE_INTEGER size;
    size.HighPart = fad.nFileSizeHigh;
    size.LowPart = fad.nFileSizeLow;
    return size.QuadPart;
}

Если вы компилируете Visual Studio и хотите избежать вызова API Win32, вы можете использовать _wstat64.

Ниже приведена версия функции _wstat64:

__int64 FileSize(const wchar_t* name)
{
    __stat64 buf;
    if (_wstat64(name, &buf) != 0)
        return -1; // error, could use errno to find out more

    return buf.st_size;
} 

Если производительность когда-либо становилась проблемой для вас, то вы должны разделить различные варианты на всех платформах, на которые вы нацелились, чтобы принять решение. Не предполагайте, что API, которые не требуют вызова CreateFile, будут быстрее. Они могут быть, но вы не узнаете, пока не придумаете.

Ответ 2

Я также жил со страхом цены, заплаченной за открытие файла, и закрыл его, чтобы получить его размер. И решил спросить счетчик производительности ^ и посмотрите, насколько дорогими являются операции.

Это количество циклов, необходимых для выполнения 1 запроса размера файла в том же файле тремя способами. Протестировано на 2 файла: 150 МБ и 1,5 ГБ. Получите +/- 10% -ные колебания, поэтому они, похоже, не зависят от фактического размера файла. (очевидно, это зависит от процессора, но это дает вам хорошую точку зрения)

  • 190 циклов - CreateFile, GetFileSizeEx, CloseHandle
  • 40 циклов - GetFileAttributesEx
  • 150 циклов - FindFirstFile, FindClose

GIST с используемым кодом ^ доступен здесь.

Как мы можем видеть из этого теста очень научный:), самый медленный на самом деле является файловым открывателем. 2-й самый медленный - это поиск файлов, а победитель - читатель атрибутов. Теперь, с точки зрения надежности, CreateFile должен быть предпочтительнее других 2. Но мне все еще не нравится концепция открытия файла, чтобы просто прочитать его размер... Если я не делая размер критичных вещей, я пойду за атрибутами.

PS: Когда у меня будет время, я попытаюсь прочитать размеры файлов, которые открываются и пишу. Но не сейчас...

Ответ 3

Еще одна опция, использующая функцию FindFirstFile

#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>

int _tmain(int argc, _TCHAR* argv[])
{
   WIN32_FIND_DATA FindFileData;
   HANDLE hFind;
   LPCTSTR  lpFileName = L"C:\\Foo\\Bar.ext";

   hFind = FindFirstFile(lpFileName , &FindFileData);
   if (hFind == INVALID_HANDLE_VALUE) 
   {
      printf ("File not found (%d)\n", GetLastError());
      return -1;
   } 
   else 
   {
      ULONGLONG FileSize = FindFileData.nFileSizeHigh;
      FileSize <<= sizeof( FindFileData.nFileSizeHigh ) * 8; 
      FileSize |= FindFileData.nFileSizeLow;
      _tprintf (TEXT("file size is %u\n"), FileSize);
      FindClose(hFind);
   }
   return 0;

}

Ответ 4

В С++ 17 есть file_size как часть стандартной библиотеки. (Тогда разработчик должен решить, как это сделать эффективно!)