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.
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é.
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)
CreateFile
, GetFileSizeEx
, CloseHandle
GetFileAttributesEx
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 ...
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;
}
Qu'en est-il GetFileSize function?
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!)