none
VB.NET récupérer, additionner la taille de divers dossiers que l'on veut copier pour utiliser dans une progressbar RRS feed

  • Discussion générale

  • Bonjour,

    Je suis entrain de réaliser un petit programme de sauvegarde qui copiera certain dossiers et fichiers par défaut (profils utilisateurs) et d'autre choisit par l'utilisateur (à l'aide d'un treeview et listbox).
    Dans l'optique de faire une progressbar, est-il possible de créer une variable et de l'incrémenter de la taille des fichiers/dossiers copiers, sans savoir bien sur à l'avance quels seront les fichiers/dossiers copiés.
    Exemple:
    Je demande l’existence de plusieurs dossier pour les copier ce qui donnerai:
    Si tel dossier existe alors
    copie("", "")
    (et là si c'est possible, récupération de la taille du dossier pour incrémentation de tel variable)
    end if

    Pareil pour la copie des profils utilisateurs sachant que je ne récupère que certain dossiers et certain fichiers dans chaque profil.
    Pareil pour les dossiers sélectionnés par l'utilisateur (listés dans une listbox après sélection dans un treeview).
    Et la taille de tous ces fichiers/dossiers irait dans une seule et même variable.

    J'arrive à récupérer et à afficher dans une msgbox la taille par exemple de tous les dossier "favoris" de chaque profil.

    Voici le code (je sais pas s'il est très correct mais il fonctionne):

    Sub Taille_Favoris()
            Dim Profil As String
            Dim Users As String = My.Application.GetEnvironmentVariable("USERPROFILE").Substring(0, My.Application.GetEnvironmentVariable("USERPROFILE").LastIndexOf("\"))
            For Each Profil In System.IO.Directory.GetDirectories(Users)
                Dim di As New DirectoryInfo(Profil)
                Dim NomProfil As String = di.Name
                Dim attributeReader As System.IO.FileAttributes
                Dim checkFile As System.IO.DirectoryInfo
                checkFile = My.Computer.FileSystem.GetDirectoryInfo(Users & "\" & NomProfil)
                attributeReader = checkFile.Attributes
                If Directory.Exists(Users & "\" & NomProfil & "\Favorites") Then
                    Try
                        If (attributeReader And System.IO.FileAttributes.System) = System.IO.FileAttributes.ReparsePoint Then
                            Continue For
                        Else
                            MsgBox(FolderSize(Users & "\" & NomProfil & "\Favorites"))
                        End If
                    Catch erreur As Exception
                        My.Computer.FileSystem.WriteAllText(Drive & NomPC & "\Erreurs.txt", vbCrLf & "-" & erreur.Message & vbCrLf, True)
                    End Try
                End If
            Next
        End Sub
     
        Public Shared Function FolderSize(ByVal path As String) As Long
            Dim Drive As String = SelectDrives.ComboBox1.SelectedItem  'Drive = la lettre que l'on sélectionne dans la combobox
            Dim NomPC As String = Environment.MachineName  'variable d'environnement qui donne le nom du pc
            Dim size As Long = 0
            Dim directoryInfo As New DirectoryInfo(path)
            Dim files As IEnumerable(Of FileInfo) = directoryInfo.GetFiles("*", SearchOption.AllDirectories)
            For Each file As FileInfo In files
                Try
                    If (file.Attributes And FileAttributes.ReparsePoint) = FileAttributes.ReparsePoint Then
                        ' Ignorer le fichier
                        Continue For
                    Else
                        size += file.Length
                    End If
                Catch erreur As Exception
                    My.Computer.FileSystem.WriteAllText(Drive & NomPC & "\Erreurs.txt", vbCrLf & "-" & erreur.Message & vbCrLf, True)
                End Try
            Next
            Return size
        End Function

    Mais mon but n'est pas de l'afficher dans une msgbox, mais de les récupérer ainsi que la taille de tous les dossiers voulu, de les additionner pour avoir le total de toute la copie pour l'utiliser dans une progressbar.

    Ou alors il y a un autre moyen plus simple d'utiliser une progressbar lors d'une copie (sans connaitre à l'avance ce que l'on va copier).

    • Type modifié Aurel Bera vendredi 13 juin 2014 11:14 disc
    mercredi 4 juin 2014 15:36

Toutes les réponses

  • Bon, j'arrive a récupérer la taille de tous les dossiers voulu , sauf pour le dossier de destination où j'utilise la fonction FolderSize(chemin du dossier de destination), il me renvoi bien un nombre mais qui ne correspond pas du tout à la taille réel de ce dossier.

    De plus je n'arrive pas à utiliser ces 2 tailles (taille totale de la copie et taille du dossier de destination) pour incrémenter la progressbar.

    Comment sait-on lorsque la copie est fini si on a pas de progressbar, n'y  a t il pas un moyen de savoir quand le processus de la copie s’arrête?

    Et ne peut-on utiliser l'activité du processus pour remplir la progressbar et aussi pour afficher dans un label.text le nom de la copie en cours?

    jeudi 5 juin 2014 22:52
  • Bonjour

    Avec quoi vous comparez la taille que vous obtenez?
    N'oubliez que vous éliminez les fichiers qui sont FileAttributes.ReparsePoint.
    Des autres raisons pour une différence peut être la taille de cluster sur le disque dur, la compression, etc....

    Bien cordialement,


    Aurel BERA, MSFT
    MSDN Community Support. LE CONTENU EST FOURNI "TEL QUEL" SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE.
    S'il vous plaît n'oubliez pas de "Marquer comme réponse" les réponses qui ont résolu votre problème. C'est une voie commune pour reconnaître ceux qui vous ont aidé, et rend plus facile pour les autres visiteurs de trouver plus tard la résolution.

    vendredi 6 juin 2014 08:00
  • Bon en fait j'ai changé mon code, j'ai opté pour le "backgroundworker" (que je ne connais pas trop) car la taille des fichiers ne prenait pas en compte tous les fichiers et était trop imparfaite.

    Avec le backgroundworker j'exécute donc mes "sub" dans le backgroundworker1_dowork, j'utilise le  BackgroundWorker1_RunWorkerCompleted pour indiquer lorsque la copie est finie et d'après le tuto que j'ai lu, pour faire avancer ma progressbar il suffirai que je fasse comme ceci:

    Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            
            Me.PGB_STATUT.Value = e.ProgressPercentage 'progressbar du toolstrip
            
        End Sub

    Mais évidement cela ne fonctionne pas.

    Je voudrais savoir donc quel est l'astuce mais aussi comment faire défiler dans un label.text les fichiers en cours de copie.

    Et dernier point, j'ai parfois certain fichiers qui ne se copient pas car ils sont en cours d'utilisation (comme certain fichier de chrome quand j'utilise internet en même temps que ma copie) et je ne trouve pas la propriété qui pourrai me faire :  "si le file est en cours d'utilisation alors continuer la boucle" comme j'ai fais pour les "reparsepoint".

    Merci de votre aide.

    J'apporte un une indication supplémentaire:

    Je sais qu'avec "Backgroundworker1.Reportprogress(x)"placé à différents endroits du "dowork" cela peut faire avancer la progressbar, mais si on ne sait pas à l'avance quelles sub seront exécutées (ex: certaines copie se font seulement si une checkbox est checked).

    Ce qui fait que la progressbar peut aller à 80% en 15 secondes et les 20% qui reste peuvent durer plusieurs minutes.

    N'y a t'il donc pas de possibilité que le backgroundworker1_PrrogressChanged = Reportprogress?

    • Modifié Bylliboy lundi 9 juin 2014 21:57
    lundi 9 juin 2014 10:07
  • Bonjour

    Pouvez-vous nous montrer le code complet pour DoWork?

    Bien cordialement,


    Aurel BERA, MSFT
    MSDN Community Support. LE CONTENU EST FOURNI "TEL QUEL" SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE.
    S'il vous plaît n'oubliez pas de "Marquer comme réponse" les réponses qui ont résolu votre problème. C'est une voie commune pour reconnaître ceux qui vous ont aidé, et rend plus facile pour les autres visiteurs de trouver plus tard la résolution.

    mardi 10 juin 2014 09:31
  • Dans l'ordre:

    - Le code récupère certaines infos, liées au pc, dans un fichier texte

    - Avant de lancer la copie des profils, l'utilisateur peut checker des dossiers dans l'arborescence du disque local pour les rajouter à la copie.

    - Copie des profils (si checkbox1 est checké, mais elle l'est par défaut à l'ouverture du programme) en ne prenant que les dossiers important.

    - Si checkbox2 est chécké (elle est aussi par défaut) alors copie de certain dossier (s'ils sont présent sur le pc, ce qui n'est pas toujours le cas) propre à mon service.

      Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            BackgroundWorker1.WorkerReportsProgress = True
            BackgroundWorker1.ReportProgress(1)
            'mes calculs très long
            'Récupérations d'infos dans un fichier texte
            If CheckBox3.Checked = True Then
                IpConfig()
                DescriptionPC()
                Imprimantes()
                InfosCheops()
            End If
            BackgroundWorker1.ReportProgress(5)
    
            'Copie des dossiers sélectionnés dans le treeview et se trouvant dans la listbox
            For Each Item In ListBox1.Items
                NomDossier = Item.ToString
                NomDossier2 = Path.GetFileName(NomDossier)
                DossierSélectionné = (NomDossier & "\\")
                DossierDestination = (Drive + NomPC & "\" & NomDossier2 & "\")
                Try
                    My.Computer.FileSystem.CopyDirectory(DossierSélectionné, DossierDestination, True)
                Catch erreur As Exception
                    ' If Directory.Exists(Drive + NomPC & "\" & NomDossier) Then
                    'If File.Exists(Drive + NomPC & "\" & NomDossier & "\") Then
                    MessageBox.Show("La Copie a échoué !" & erreur.GetBaseException.Message, "Erreur")
                    '  End If
                    '  End If
                End Try
            Next
            BackgroundWorker1.ReportProgress(20)
            ' ListBox1.Items.Clear()
    
            'Copie des profils
            If CheckBox1.Checked = True Then
                Copie_Google()
                BackgroundWorker1.ReportProgress(25)
                Copie_Mozilla()
                BackgroundWorker1.ReportProgress(30)
                Copie_Thunderbird()
                BackgroundWorker1.ReportProgress(35)
                Copie_Favorites()
                BackgroundWorker1.ReportProgress(40)
                Copie_Videos()
                BackgroundWorker1.ReportProgress(45)
                Copie_Pictures()
                BackgroundWorker1.ReportProgress(50)
                Copie_Music()
                BackgroundWorker1.ReportProgress(55)
                Copie_Desktop()
                BackgroundWorker1.ReportProgress(60)
                Copie_Downloads()
                BackgroundWorker1.ReportProgress(65)
                Copie_Docs()
                BackgroundWorker1.ReportProgress(70)
            End If
    
            ' Copies des dossier "PP":
            If CheckBox2.Checked = True Then
                If Directory.Exists("C:\ORAWIN") Then
                    My.Computer.FileSystem.CopyFile("C:\ORAWIN\NETWORK\ADMIN\TNSNAMES.ORA", Drive & NomPC & "\TNSNAMES.ORA", True)
                End If
                BackgroundWorker1.ReportProgress(73.75)
                If Directory.Exists("C:\baselrp") Then
                    My.Computer.FileSystem.CopyDirectory("C:\baselrp", Drive & NomPC & "\baselrp", True)
                End If
                BackgroundWorker1.ReportProgress(77.5)
                If Directory.Exists("C:\CLIENTS") Then
                    My.Computer.FileSystem.CopyDirectory("C:\CLIENTS\LRPPN3", Drive & NomPC & "\CLIENTS\LRPPN3", True)
                End If
                BackgroundWorker1.ReportProgress(81.25)
                If Directory.Exists("C:\Documents Locaux") Then
                    My.Computer.FileSystem.CopyDirectory("C:\Documents Locaux", Drive & NomPC & "\Documents Locaux", True)
                End If
                BackgroundWorker1.ReportProgress(85)
                If Directory.Exists("C:\Stic") Then
                    My.Computer.FileSystem.CopyDirectory("C:\Stic\LRP", Drive & NomPC & "\Stic\LRP", True)
                End If
                BackgroundWorker1.ReportProgress(8.75)
                If Directory.Exists("C:\Omega") Then
                    My.Computer.FileSystem.CopyDirectory("C:\Omega", Drive & NomPC & "\Omega", True)
                End If
                BackgroundWorker1.ReportProgress(92.5)
                If Directory.Exists("C:\Agenda") Then
                    My.Computer.FileSystem.CopyDirectory("C:\Agenda", Drive & NomPC & "\Agenda", True)
                End If
                BackgroundWorker1.ReportProgress(96.25)
                If Directory.Exists("C:\Idapi") Then
                    My.Computer.FileSystem.CopyFile("C:\IDAPI\IDAPI.CFG", Drive & NomPC & "\IDAPI\IDAPI.CFG", True)
                End If
                BackgroundWorker1.ReportProgress(99)
            End If
            BackgroundWorker1.ReportProgress(100)
        End Sub

    Et comme vous le voyez j'ai mis des ReportProgress partout pour incrémenter la progressbar mais ce n'est pas l'idéal que je voudrai, car suivant si les dossiers existent ou sélectionné (ou pas) la progressbar peut (comme je l'ai déjà dit) donc avancer d'un coup jusqu'à 70% puis finir les 30% en plusieurs minutes.

    Exemple d'une des sub utilisées pour les copie des dossiers de chaque profil:

     Sub CopierDossier(ByVal source As DirectoryInfo, ByVal destination As DirectoryInfo)
            destination.Create()
            ' Copier tous les fichiers du répertoire
            For Each fichier In source.GetFiles()
                Try
                    If (fichier.Attributes And FileAttributes.ReparsePoint) = FileAttributes.ReparsePoint Then
                        ' Ignorer le fichier
                        Continue For
                    Else
                        ' Copier le fichier
                        fichier.CopyTo(destination.FullName + fichier.Name, FileIO.UIOption.AllDialogs)
    
                    End If
                Catch erreur As Exception
                    My.Computer.FileSystem.WriteAllText(Drive & NomPC & "\Erreurs.txt", vbCrLf & "-" & erreur.Message & vbCrLf, True)
                End Try
            Next
    
            ' Copier récursivement les fichiers du répertoire
            For Each répertoire In source.GetDirectories()
                If (répertoire.Attributes And FileAttributes.ReparsePoint) = FileAttributes.ReparsePoint Then
                    Continue For
                Else
                    CopierDossier(répertoire, New DirectoryInfo(destination.FullName + répertoire.Name + "\"))
                End If
            Next
        End Sub
    
        Sub Copie_Docs()
            Dim Profil As String
            Dim Users As String = My.Application.GetEnvironmentVariable("USERPROFILE").Substring(0, My.Application.GetEnvironmentVariable("USERPROFILE").LastIndexOf("\"))
            For Each Profil In System.IO.Directory.GetDirectories(Users)
                Dim di As New DirectoryInfo(Profil)
                Dim NomProfil As String = di.Name
                Dim Profildestination As String = (Drive & NomPC & "\Profils\" & NomProfil)
                Dim checkFile As System.IO.DirectoryInfo
                checkFile = My.Computer.FileSystem.GetDirectoryInfo(Users & "\" & NomProfil & "\Documents\")
                Dim attributeReader As System.IO.FileAttributes
                attributeReader = checkFile.Attributes
    
                If Directory.Exists(Users & "\" & NomProfil & "\Documents") Then
                    My.Computer.FileSystem.CreateDirectory(Drive & NomPC & "\Profils\" & NomProfil & "\Documents\")
                    Try
                        If (attributeReader And System.IO.FileAttributes.ReparsePoint) = System.IO.FileAttributes.ReparsePoint Then
                            Continue For
                        Else
                            CopierDossier(New DirectoryInfo(Users & "\" & NomProfil & "\Documents"), New DirectoryInfo(Profildestination & "\Documents\"))
                        End If
                    Catch erreur As Exception
                        My.Computer.FileSystem.WriteAllText(Drive & NomPC & "\Erreurs.txt", vbCrLf & "-" & erreur.Message & vbCrLf, True)
                    End Try
                End If
            Next
        End Sub

    • Modifié Bylliboy mardi 10 juin 2014 13:45
    mardi 10 juin 2014 13:34
  • Je dirais de calculer la taille totale des fichiers/répertoires à copier, et rapporter un progress de NoBytesDejaCopiees/NoBytesTotal.
    Mais vous devez connaitre la taille totale des fichiers à copier qui change en function de selection dans checkbox.

    Bien cordialement, 

     

    Aurel BERA, MSFT
    MSDN Community Support. LE CONTENU EST FOURNI "TEL QUEL" SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE.
    S'il vous plaît n'oubliez pas de "Marquer comme réponse" les réponses qui ont résolu votre problème. C'est une voie commune pour reconnaître ceux qui vous ont aidé, et rend plus facile pour les autres visiteurs de trouver plus tard la résolution.

    mardi 10 juin 2014 13:47
  • Donc il faudrait que je revienne sur ma première intention qui est plus fastidieuse, et que je fasse un double de mon dowork sauf qu'au lieu de copier, l'action sera de récupérer la taille des fichiers ou répertoires à copier, dans une variable pour l'utiliser dans la progressbar.

    Dans certain forum j'en vois certain qui utilisent le nombre total de fichiers plutôt que la taille, celon vous qu'est ce qui est préférable, la taille ou le compte des fichiers?

    mardi 10 juin 2014 15:24
  • Utiliser la taille des fichiers c'est plus exact. Utiliser le nombre des fichiers produit le même comportement que vous avez déjà : 1 fichier de 1 octet est assez important que un fichier de 1 GB. Si par exemple vous voulez copier les deux, le progressa avance à 50% après avoir copiée le fichier de 1 octet, et pour arriver à 100% vous devez attende le fin de la copie du dernier fichier. Le temps pour copier 1 GO est plus important que le temps pour copier 1 octet.

    De l'autre cote, dans ce cas extrême, le progressbar avance très peu après avoir copié le fichier de 1 octet et vous attendez le fin de la copie du deuxième fichier pour atteindre 100%.

    L’avantage d’utiliser le nombre de fichiers est que c’est moins couteux comme temps de compter les fichiers que de récupérer la taille totale. 

     Bien cordialement,


    Aurel BERA, MSFT
    MSDN Community Support. LE CONTENU EST FOURNI "TEL QUEL" SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE.
    S'il vous plaît n'oubliez pas de "Marquer comme réponse" les réponses qui ont résolu votre problème. C'est une voie commune pour reconnaître ceux qui vous ont aidé, et rend plus facile pour les autres visiteurs de trouver plus tard la résolution.

    mercredi 11 juin 2014 06:40
  • Bon finalement j'utilise le nombre des fichiers (et non plus la taille) pour incrémenter ma progressbar, (à chaque fois qu'un fichier est copier -> progressbar.performstep) qui fonctionne très bien si je n'utilise pas de backgrounworker, mais avec, j'ai le message d'erreur suivant:
    "Opération inter-threads non valide*: le contrôle '' a fait l'objet d'un accès à partir d'un thread autre que celui sur lequel il a été créé."
    A mon avis je devrai utiliser le "invoke" mais j'ai beau lire les tutos, j'y comprends rien.
    Y a t il une âme charitable qui pourrai m'expliquer (avec des mots simples) comment l'utiliser avec ma progressbar et mon BGW.
    Merci
    vendredi 13 juin 2014 23:58
  • Je vais clore ce poste car j'ai trouvé ma façon d'incrémenter ma progresbar en utilisant, non pas la taille, mais le nombre de fichiers comptabilisés dans la copie.

    Pour ceux que ça interesse, voici la fonction que j'ai utilisé pour compter les fichiers de chaque dossiers copier.

     Function NbrFichiers(ByVal DirPath As String, Optional IncludeSubFolders As Boolean = True) As Long
            Dim Nfiles As Integer
            Dim objFileInfo As FileInfo
            Dim objDir As DirectoryInfo = New DirectoryInfo(DirPath)
            Dim objSubFolder As DirectoryInfo
            Try
                For Each objFileInfo In objDir.GetFiles()
                    Nfiles += 1
                Next
                'call recursively to get sub folders
                'if you don't want this set optional
                'parameter to false
                If IncludeSubFolders Then
                    For Each objSubFolder In objDir.GetDirectories()
                        Nfiles += NbrFichiers(objSubFolder.FullName)
                    Next
                End If
            Catch erreur As Exception
                My.Computer.FileSystem.WriteAllText(Drive & NomPC & "\Erreurs.txt", vbCrLf & "-" & erreur.Message & vbCrLf, True)
            End Try
            Return Nfiles
        End Function

    Ma progressbar fonctionne très bien donc sans backgroundworker, mais comme j'aimerai garder ce fameux bgw, je vais lancer un nouveau poste pour traiter ce problème.

    dimanche 15 juin 2014 21:34
  • je ne trouve plus le truc pour marquer comme réponse et cloturer ce poste
    lundi 16 juin 2014 15:52