Проверить размер файла, не открывая файл в C ++? - PullRequest
28 голосов
/ 24 января 2012

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

Ответы [ 5 ]

44 голосов
/ 24 января 2012

Вам следует позвонить 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 и хотите избежать вызова Win32 API, тогда вы можете использовать _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, были быстрее. Они могут быть, но вы не узнаете, пока не рассчитаете время.

28 голосов
/ 04 августа 2013

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

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

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

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

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

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

9 голосов
/ 24 января 2012

Другой вариант с использованием функции 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;

}
2 голосов
/ 18 сентября 2017

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

1 голос
/ 24 января 2012

А как насчет функции GetFileSize ?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...