Intégrer une API dans VBA pour récuperer la taille de fichier de plusieurs giga

Résolu
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007 - 21 févr. 2006 à 15:53
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007 - 10 mars 2006 à 13:27
Bonjour à tous,

J'ai essayé désespérement de récupérer la taille de plusieurs fichiers de plusieurs Go (jusqu'à 30) en utilisant les FSO, la FileSearch mais bien évidement, vu le volume, j'ai des résultats faux... Il semble qu'il y ai la possibilitée de résoudre ce problème en integrant une API que j'ai trouvé à l'adresse suivante (http://www.mentalis.org/apilist/GetFileSize.shtml) mais lorsque je teste, ca me donne -1... Est-ce que quelqu'un peu me dire comment intégrer l'API correctement dans mon code (ci-dessous celui de base)

Sub TailleBAL()
'Déclaration des variables et objet
Dim IntExSV, IntExGS, IntRow As Integer
Dim Fso, Dossier As Object, FS As Double
Dim Chemin(4)
Chemin(1) = "g$"
Chemin(2) = "i$"
Chemin(3) = "k$"
Chemin(4) = "m$"
Set Fso = CreateObject("Scripting.FileSystemObject")
IntRow = 26
For IntExSV = 1 To 2
For IntExGS = 1 To 2
'Spécification du chemin des dossiers
Set Dossier = Fso.GetFolder("\\exchange" & IntExSV & "" & Chemin(IntExSV) & "\SV" & IntExSV & "-GS" & IntExGS)
'Instruction pour connaitre la taille d'un répertoire
FS = Dossier.Size
'Saisie des résultats dans le tableau
Range("B" & IntRow).Value = "" & FS
IntRow = IntRow + 1
Next IntExGS
Next IntExSV
Set Fso = Nothing
End Sub

Merci par avance.

13 réponses

Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
22 févr. 2006 à 15:01
effectivement Vb ne sait pas gérer des fichiers de taille supérieure à un Long.

je suppose qu'en Vba c'est la même chose.

il faut donc bien utiliser les API's.







Const MAX_PATH = 260

Const INVALID_HANDLE_VALUE = -1



Private Type WIN32_FIND_DATA

dwFileAttributes As Long

ftCreationTime As Currency

ftLastAccessTime As Currency

ftLastWriteTime As Currency

nFileSizeHigh As Long

nFileSizeLow As Long

dwReserved0 As Long

dwReserved1 As Long

cFileName As String * MAX_PATH

cAlternate As String * 14

End Type



Private Declare Function FindFirstFile Lib "kernel32" Alias
"FindFirstFileA" (ByVal lpFileName As String, lpFindFileData As
WIN32_FIND_DATA) As Long

Private Declare Function FindNextFile Lib "kernel32" Alias
"FindNextFileA" (ByVal hFindFile As Long, lpFindFileData As
WIN32_FIND_DATA) As Long

Private Declare Function FindClose Lib "kernel32" (ByVal hFile As Long) As Long



Private Sub Command1_Click()

Dim FindData As WIN32_FIND_DATA

Dim taille As Double

Dim nom As String

Dim hfind As Long



nom = "C:\chemin\monfichier.txt"

hfind = FindFirstFile(nom, FindData)

If hfind = INVALID_HANDLE_VALUE Then

MsgBox "Erreur Lecture Fichier"

Exit Sub

End If

FindClose hfind



taille = FindData.nFileSizeHigh * 2 ^ 32 + FindData.nFileSizeLow

MsgBox taille



End Sub


Daniel
3
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
24 févr. 2006 à 19:48
Salut,

apparemment seul fso sait le faire

pas trouvé d'autres fonctions capable de renvoyer la taille d'un répertoire

il y a bien GetDiskFreeSpace mais c'est pour l'unité disque.





pour info je te met GetFileSizeEx qui renvoit la taille en Currency,
contrairement à GetFileSize qui renvoit la taille sur 2 Longs

mais en plus il a besoin d'un Handle de fichier:




Const GENERIC_READ = &H80000000


Const FILE_SHARE_READ = &H1


Const OPEN_EXISTING = 3





Private Declare Function CreateFile Lib
"kernel32" Alias "CreateFileA" (ByVal lpFileName As String, ByVal
dwDesiredAccess As Long, ByVal dwShareMode As Long,
lpSecurityAttributes As Any, ByVal dwCreationDisposition As Long, ByVal
dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long


Private Declare Function GetFileSizeEx Lib "kernel32" (ByVal hFile As Long, lpFileSize As Currency) As Boolean


Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long





Private Sub Command1_Click()


Dim hFile As Long, nSize As Currency





hFile = CreateFile("c:\windows\explorer.exe", GENERIC_READ,
FILE_SHARE_READ, ByVal 0&, OPEN_EXISTING, ByVal 0&, ByVal
0&)





GetFileSizeEx hFile, nSize





CloseHandle hFile





MsgBox "Size:" + Str$(nSize * 10000) + " bytes"





End Sub





après test, fso est nettement moins rapide qu'une recherche fichier par fichier,

mais renvoit la même valeur, somme totale des fichiers

j'ai testé avec avec Dir() et FileLen() n'ayant pas de fichiers > 2.147 Go



pour avoir la taille réelle occupée, faut tenir compte des clusters.

savoir le nombre de secteurs par clusters (ce que donne GetDiskFreeSpace)

et faire le calcul fichier par fichier:

Cluster = (nombre de clusters par secteur) * 512

TotalCluster = TotalCluster + (Taille + Cluster - 1) \ Cluster


Daniel
3
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
8 mars 2006 à 14:55
Salut,

- fso rapide ???

j'en doûte



- API #2

je te fais confiance



- API #1

c'est dans la méthode de calcul

on peut pas transformer les deux Long (High et Low) en Currency

parce que ce n'est pas dans le bon sens (Big Endian au lieu de Little Endian)

il faut donc interpréter le résultat,

on sait qu'il n'y a pas de taille négative,

or au dessus de 2 147 483 647 la valeur dans le Long est considérée comme

du négatif:



Const CM As Currency = 4294967296#

Dim taille As Currency



taille = FindData.nFileSizeLow

' si négatif, on corrige

If taille < 0 Then taille = CM + taille



' on peut encore ajouter le High si la taille peut être > 4,29 milliards

taille = taille + FindData.nFileSizeHigh * CM


Daniel
3
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
10 mars 2006 à 12:15
Bonjour,


bigre, tu dois avoir de sacrès gros fichiers !

celle là doit marcher à tous les coups (limitée à 2^63 quand même, soit 9 milliards de milliards, ça devrait suffire)

donc version #2 mais sans le test > CM qui se fera jamais



'on prend la partie basse:

TailleF@ = FindData.nFileSizeLow



'si la partie basse est négative, on la rend positive

If TailleF@ < 0 Then TailleF@ = CM + TailleF@ 'en fait c'est une soustraction



'si la partie haute n'est pas nulle, faut la prendre en compte

TailleF@ = TailleF@ + FindData.nFileSizeHigh * CM



'si la partie haute est négative

'je crois qu'on peut s'arrêter là



'on cumule dans la taille totale

TailleT@ = TailleT@ + TailleF@


Daniel
3

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
21 févr. 2006 à 19:46
Salut
Pourquoi faire simple quand on peut faire compliqué !

Pas la peine d'utiliser FSO pour ça, VBA a une instruction pour récupérer en octet la taille d'un fichier :
FileLen("C:\mon fichier.txt")
Pour ensuite convertir la taille Octets en multiples :
ko = 1024 octets
Mo = 1024 ko
Go = 1024 Mo
To = 1024 Go
Comme tu dois utiliser des fichiers de grandes tailles : 30 Go = 32.212.254.720 octets, ça va dépasser la capacité des variables de type Long (2.147.483.647 en VB6)
Il faudra donc bien penser à dimensionner ta variable de réception en type Currency et faire les opération avec des constantes typées aussi :
J'ai testé cet exemple sur ma machine :
Dim cTaille1 As Currency
Dim sTaille2 As Single
cTaille1 = FileLen("C:\PageFile.sys")
ctaille2 = CSng(cTaille1 / 1024@ / 1024@ / 1024@)
MsgBox cTaille1 & " octets = " & ctaille2 & " Go"

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Le savoir est la seule matière qui s'accroit quand on la partage. (Socrate)
0
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007
22 févr. 2006 à 12:10
Bonjour,

Merci pour ton aide mais hélas ca me donne le même genre de problème... Sauf erreur de ma part, l'erreur vient du fait que l'instruction FileLen retourne une valeur de type Long. Donc même si je passe par une variable intermédiaire plus grande, le contenue de celle-ci lorsque j'aurai collé la taille du fichier ne seras jamais plus grande qu'un Long surtout après avoir été divisé plusieurs fois par 1024.

J'ai quand même tester le code que tu as mis et la msgbox me retourne les infos suivantes :
-870148306 octets = -0,8103887 Go
Mon fichier sur lequel j'ai teste le code fait 3.3 go (affichage explorateur windows)

Tu aurais une idée STP ?
0
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007
24 févr. 2006 à 10:17
Merci infiniment ! Ca marche merveilleusement ! Ca m'enlève le rosier du pied :P

Pour le coté bizzarerie, je me suis fait un fichier de test de 3.3 Go pour lequel il me donne une valeur négative... (-8.et quelques) ! Mais ca passe pour les fichiers qui m'interesse, c'est le principal.

Question subsidaire : est-il possible d'adapter le code pour avoir la taille d'un répertoire directement ou éventuellement de plusieurs fichiers (*.log par exemple) ?
0
cs_Jack Messages postés 14006 Date d'inscription samedi 29 décembre 2001 Statut Modérateur Dernière intervention 28 août 2015 79
24 févr. 2006 à 17:22
Salut
C'est vrai, je n'avait pas tilté sur le type de variable de retour du FileLen.
Pour ta dernière question, ça m'étonnerai qu'il y ait une fonction toute faite. Il va te falloir scanner le répertoire (avec FindNextFile) à la recherche de tes LOG et additionner leurs tailles.

Vala
Jack, MVP VB
NB : Je ne répondrai pas aux messages privés

Champion du monde de boule de cristal - 2005
Le savoir est la seule matière qui s'accro
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
24 févr. 2006 à 18:26
pourtant fso renvoit bien des tailles supérieures à 2 giga

ce n'est pas la place occupée, mais la somme des tailles des fichiers, sans tenir compte des clusters.



Dim fso As New FileSystemObject

Dim dossier As String

Dim taille As Double



dossier = "C:\WINDOWS"

taille = fso.GetFolder(dossier).Size

MsgBox taille


Daniel
0
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007
8 mars 2006 à 13:41
Bonjour,

Voici un "petit retour d'expérience" concernant les différents codes que j'ai tester pour récupérer la taille de fichers volumineux :P

FSO : méthode rapide qui gère les fichiers > à 3 Go mais qui plante en cas d'accès non authorisé (répertoire "system volume information" par exemple)
FS : méthode longue qui ne guère pas les fichiers > 3 Go
API #1 (voir 1er réponse accepté) : la gestion des fichiers > 3 Go est ok mais bizarrement, lorsque le script arrive à un fichier .EDB (messagerie Exchange), celle-ci retourne une valeur négative... :(
API #2 (voir 2eme réponse accepté) : rapidité moyenne, gestion des fichiers > 3 Go ok ! Seul bémol (dans mon environnement), ca marche très bien sur mon DD mais dès que je passe sur les fichiers de mon serveur, ca me retourne 0 octet... :/

Voilà, c'était juste pour info. Mais si quelqu'un a une solution ou une idée pour l'une de ces méthodes (sauf la FS (FileSearch) que j'ai laissé tombé), je suis preneur.

@+
0
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007
8 mars 2006 à 16:33
Merci pour l'info ! Je teste ca demain !

Pour les FSO, c'est vrai que j'avais déjà lu que ce n'était pas la plus rapide mais, dans mon environnement, c'est la plus rapide ! Si, si ! Jurée craché ! (A part le problème d'autorisation bien sur :P) Peut être dur à croire mais pourtant véridique !
0
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007
10 mars 2006 à 11:45
Salut,

Effectivement, le problème est corrigé ! J'ai maintenant la bonne taille pour mes fichiers .EDB qui posaient problèmes. Sauf que maintenant ce sont ceux qui marchaient bien avant qui n'ont plus la bonne taille :( Je m'explique :

- Si j'utilise la formule :
taille = FindData.nFileSizeHigh * 2 ^ 32 + FindData.nFileSizeLow
de la 1er API, la taille de mon fichier est plus grande que prévue.
- Si j'utilise dans la formule :
taille = FindData.nFileSizeLow
ou
taille = taille + FindData.nFileSizeHigh * CM
en cas de fichier volumineux ben... C'est l'inverse : la taille affiché est plus petit que la réalité !

Je me demande si à force je ne m'embrouille pas un peu non plus... Dans le doute, je mets ci-dessous mon code au cas ou il y aurait une erreur :

Do While Fichier$ <> ""
hfind = FindFirstFile(Chemin$ & "" & Fichier$, FindData)
If hfind = INVALID_HANDLE_VALUE Then MsgBox "Erreur de lecture du fichier"
FindClose hfind
'TailleF@ = FindData.nFileSizeHigh * 2 ^ 32 + FindData.nFileSizeLow 'Version #1
TailleF@ = FindData.nFileSizeLow 'Version #2
If TailleF@ < 0 Then TailleF@ = CM + TailleF@
If TailleF@ > CM Then TailleF@ = TailleF@ + FindData.nFileSizeHigh * CM
TailleT@ = TailleT@ + TailleF@
Fichier$ = Dir$
Loop

Merci encore !
0
Cybertat Messages postés 25 Date d'inscription vendredi 15 juillet 2005 Statut Membre Dernière intervention 8 septembre 2007
10 mars 2006 à 13:27
CA MARCHE !!!

Sans erreur de fichier trop gros, ni trop petit, sans délai d'attente de résultat extravagant, sans problème d'autorisation farfelue ! Le plus simplement et clairement possible !

CA MARCHE !!!

Un gros gros, giganstesque, phénoménal, titanesque MERCI pour m'avoir aider et accompagner dans la résolution de ce problème !!!
0
Rejoignez-nous