web-dev-qa-db-fra.com

Vérifier la taille du fichier sans ouvrir le fichier en c ++?

J'essaie d'obtenir la taille d'un fichier volumineux (12 Go +) et je ne veux pas l'ouvrir pour le faire, car je suppose que cela prendrait beaucoup de ressources. Y a-t-il une bonne API pour le faire? Je suis dans un environnement Windows. 

26
user1167566

Vous devriez appeler GetFileSizeEx qui est plus facile à utiliser que l'ancien GetFileSize . Vous devrez ouvrir le fichier en appelant CreateFile, mais c’est une opération peu coûteuse. Votre hypothèse selon laquelle ouvrir un fichier coûte cher, même un fichier de 12 Go, est fausse.

Vous pouvez utiliser la fonction suivante pour faire le travail:

__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;
}

D'autres appels d'API vous renverront la taille du fichier sans vous obliger à créer un descripteur de fichier, notamment GetFileAttributesEx . Cependant, il est parfaitement plausible que cette fonction ouvre simplement le fichier en arrière-plan.

__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;
}

Si vous compilez avec Visual Studio et souhaitez éviter d'appeler les API Win32, vous pouvez utiliser _wstat64 .

Voici une version de la fonction basée sur _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;
} 

Si les performances sont devenues un problème pour vous, vous devez planifier les différentes options sur toutes les plates-formes que vous ciblez afin de prendre une décision. Ne présumez pas que les API qui ne vous obligent pas à appeler CreateFile seront plus rapides. Ils pourraient être, mais vous ne saurez pas jusqu'à ce que vous avez chronométré.

42
David Heffernan

J'ai aussi vécu avec la peur du prix à payer pour ouvrir et fermer un fichier juste pour avoir sa taille. Et a décidé de demander au performance compteur ^ et de voir à quel point les opérations sont coûteuses.

C'est le nombre de cycles requis pour exécuter une requête de taille de fichier sur le même fichier avec les trois méthodes. Testé sur 2 fichiers: 150 Mo et 1,5 Go. Vous avez obtenu des fluctuations de +/- 10% afin qu'elles ne semblent pas être affectées par la taille réelle du fichier. (évidemment, cela dépend du processeur mais cela vous donne un bon point de vue)

  • 190 cycles - CreateFile, GetFileSizeEx, CloseHandle
  • 40 cycles - GetFileAttributesEx
  • 150 cycles - FindFirstFile, FindClose

The Gist avec le code utilisé ^est disponible ici.

Comme nous pouvons le constater avec ce test hautement scientifique :), le plus lent est en fait l’ouvre-fichier. 2e lent est le Finder de fichier tandis que le gagnant est le lecteur d'attributs. Maintenant, en termes de fiabilité, CreateFile devrait être préféré aux 2 autres. Mais je n'aime toujours pas le concept d'ouvrir un fichier juste pour lire sa taille ... À moins que je ne fasse des choses critiques de taille, Je vais pour les attributs .

PS: Quand j'aurai le temps, j'essaierai de lire la taille des fichiers ouverts et sur lesquels j'écris. Mais pas maintenant ...

26
CodeAngry

Une autre option utilisant la fonction 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;

}
9
RRUZ

Qu'en est-il GetFileSize function?

1
Armen Tsirunyan

A partir de C++ 17, il existe file_size dans la bibliothèque standard. (Ensuite, l'implémenteur doit décider comment le faire efficacement!)

0
Davis Herring