IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Lecture d'un gros fichier


Sujet :

VB.NET

  1. #1
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Points : 45
    Points
    45
    Par défaut Lecture d'un gros fichier
    Bonjour à tous,

    J'essai tant bien que mal d'afficher une barre de progression pendant la lecture d'un fichier. J'utilise donc un thread avec des délégués pour définir la valeur maximum de la barre de progression, et afficher la progression pendant la lecture.

    Le seul problème (qui peut paraître simple surement à vos yeux) et que je n'arrive pas à définir la valeur maximale de la barre de progression, j'ai soit des dépassement de capacité, soit une valeur trop grande...

    Voici le code de mon thread :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
     
                Dim lProcessedLength As Long = 0
                Dim fileLength As Long = 0
                Dim iProgressValue As Long = 0
                Using fs As FileStream = File.Open("C:\fichier.iso", FileMode.Open, FileAccess.ReadWrite)
                    fileLength = fs.Length
                    Using bs As BufferedStream = New BufferedStream(fs)
                        Using sr As StreamReader = New StreamReader(bs)
                            Dim ligne As String = ""
                            ligne = sr.ReadLine
                            lProcessedLength += ligne.Length
                            iProgressValue = Convert.ToInt32((lProcessedLength / fileLength) * 100)
                            tdlg.ShowProgressPercent(iProgressValue)
                            While ligne IsNot Nothing
                                If cancel = True Then
                                    Exit Sub
                                End If
                                lProcessedLength += ligne.Length
                                ' get the percent of the file that we have completed...
                                iProgressValue = Convert.ToInt32((lProcessedLength / fileLength) * 100)
                                tdlg.ShowProgressPercent(iProgressValue)
                                ligne = sr.ReadLine
                            End While
                            sr.Close()
                            sr.Dispose()
                        End Using
                        bs.Close()
                        bs.Dispose()
                    End Using
                    fs.Close()
                    fs.Dispose()
                End Using
    Dans ce code, j'ai directement mis la taille du fichier dans la mise à jour de la valeur maximale de la barre de progression (fichier de 4Go) Et le File.lentgh provoque un dépassement de capacité.

    Pouvez vous m'aidez s'il vous plait ?

    Merci à tous !

  2. #2
    Membre expérimenté
    Homme Profil pro
    Développeur .Net / Delphi
    Inscrit en
    Juillet 2002
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .Net / Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2002
    Messages : 738
    Points : 1 745
    Points
    1 745
    Par défaut
    Bonjour,

    Plusieurs choses clochent dans ce code :
    - La lecture des lignes (ligne = sr.ReadLine) est en dehors de la boucle : La boucle ne fait qu'incrémenter la ProgressBar ??!
    - La variable lProcessedLength n'est pas utilisée : La ProgressBar est incrémenté de 1 à chaque boucle et non pas en fonction de lProcessedLength ...

    Concernant la valeur max de la ProgressBar, si le fichier peut atteindre 4Go (ça va être long comme traitement !!!) ça va dépasser. Il va falloir utiliser une méthode pour calculer la valeur de progression de la ProgressBar et sa valeur max afin qu'elles soient proportionnelles à la progression de lecture et à la taille du fichier (type pourcentage).

    eb.

  3. #3
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    tu peux mettre le progressbar.maximum à une valeur autre que la taille du fichier et faire un produit en crois pour trouver la valeur à y mettre

    si le progressbar fait 300 pixels de long, mettre 300 en max a un sens dans le sens ou faire avancer de 1 fait avancer d'un pixel (alors que sur 4 millions faire avancer de 1 ne fait pas avancer du tout le progressbar)
    tu peux aussi gérer en pourcentage et mettre 100 dans max (ca sera quand même moins fin)
    et si tu ne veux t'embeter à gérer le nombre de pixels tu mets arbitrairement 1000 dans max, ca sera fin et simple à calculer

    après tu connais le nombre d'octets du fichier et tu connais le nombre d'octets lus
    enfin toi tu lis des lignes, mais le nombre d'octets peut en etre déduis

    et sinon mettre à jour le progressbar à chaque ligne est une perte de temps, donc surement une perte de performance, le faire toutes les x lignes suffit
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  4. #4
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Merci pour vos réponses, j'ai donc modifier la lecture des lignes à l'intérieur de la boucle (c'est vrai que sinon c'était un peu nul comme code ) et j'ai essayer de calculer la progression; J'ai donc ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    Dim lProcessedLength As Long = 0
                Dim fileLength As Long = 0
                Using fs As FileStream = File.Open("C:\fichier.iso", FileMode.Open, FileAccess.ReadWrite)
                    fileLength = fs.Length
                    Using bs As BufferedStream = New BufferedStream(fs)
                        Using sr As StreamReader = New StreamReader(bs)
                            Dim ligne As String = ""
                            ligne = sr.ReadLine
                            While ligne IsNot Nothing
                                If cancel = True Then
                                    Exit Sub
                                End If
                                lProcessedLength += ligne.Length
                                ' get the percent of the file that we have completed...
                                Dim iProgressValue As Integer = Convert.ToInt32((lProcessedLength / fileLength) * 100)
                                tdlg.ShowProgressPercent(iProgressValue)
                                ligne = sr.ReadLine
                            End While
                            sr.Close()
                            sr.Dispose()
                        End Using
                        bs.Close()
                        bs.Dispose()
                    End Using
                    fs.Close()
                    fs.Dispose()
                End Using
    Mais le traitement se termine avec une barre remplie à 94%, ai-je oublié quelque chose ?

    Merci encore !

  5. #5
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Désolé post en double problème d'envoi de formulaire...

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    pas regardé le code mais tu as surement oublié de faire +2 à chaque ligne (un saut de ligne c'est 2 caractères, et vu que tu découpes par ligne ils sont supprimés te ta chaine de caractère)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  7. #7
    Membre expérimenté
    Homme Profil pro
    Développeur .Net / Delphi
    Inscrit en
    Juillet 2002
    Messages
    738
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Développeur .Net / Delphi
    Secteur : Finance

    Informations forums :
    Inscription : Juillet 2002
    Messages : 738
    Points : 1 745
    Points
    1 745
    Par défaut
    Et je reviens sur ce que disait Pol63 :
    mettre à jour le progressbar à chaque ligne est une perte de temps, donc surement une perte de performance, le faire toutes les x lignes suffit
    Donc, pour gagner en perf, calculer le pourcentage toutes les x lignes et appeler tdlg.ShowProgressPercent uniquement si ce poucentage est réellement modifié ...

  8. #8
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Pol63, même résultat en ajoutant +2 a chaque ligne... Se termine a 94%

  9. #9
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Bonjour.

    Je vois plusieurs problèmes :
    * Line.Length exprime la longueur de la chaîne en caractères UTF-16, pas en octets. Ça ne fonctionne que si tous les caractères n'occupent qu'un octet dans la source (A-z 0-9 etc) mais certains peuvent en occuper davantage (comme les caractères accentués dans une source Utf-8). Utiliser Stream.Position serait une meilleure idée et c'est peut-être là l'origine du problème (et pas besoin de +2 du coup).

    * EN C# diviser un entier par un entier donne un entier, ce qui ici ferait toujours une progression de zéro. En VB cette division produit apparemment un réel mais dans dans le doute j'utiliserais plutôt la forme (100 * lProcessedLength) / fileLength. Probablement inutile ici mais je préfère le signaler au cas où.

    * La barre de progression n'est pas mise à jour en cas d'annulation.

  10. #10
    Expert confirmé
    Avatar de wallace1
    Homme Profil pro
    Administrateur systèmes
    Inscrit en
    Octobre 2008
    Messages
    1 966
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Administrateur systèmes
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 966
    Points : 4 005
    Points
    4 005
    Billets dans le blog
    7
    Par défaut
    Bonsoir wmenant,

    J'espère que ma source t'inspirera :


    ----> La composition du programme de type "WindowsForm" :

    - 1 formulaire (Frm_Main) :

    - 1 backgroundWorker (backgroundWorker1) :

    BackgroundWorker.WorkerReportsProgress = True
    BackgroundWorker.WorkerSupportsCancellation = True

    - 1 bouton (Button1) :

    Button1.text = "Lancer"

    - 1 ProgressBar (ProgressBar1)


    ----> L'interface du programme : :







    REMPLACES LA VALEUR DE LA VARIABLE : _BigFilePath par ton chemin de fichier

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
     
    Imports System.IO
     
    Public Class Frm_Main
     
        Private _InProgress As Boolean
        Private _BigFilePath As String = "C:\Windows 8.1 AIO.iso"
     
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            If Button1.Text = "Annuler" Then
                BackgroundWorker1.CancelAsync()
            Else
                If Not BackgroundWorker1.IsBusy Then
                    BackgroundWorker1.RunWorkerAsync(_BigFilePath)
                    _InProgress = True
                    Button1.Text = "Annuler"
                End If
            End If
        End Sub
     
        Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim fs As New FileStream(e.Argument.ToString, FileMode.Open)
            Dim bytesRead As Integer = 0
            Dim bytesSoFar As Long = 0
            Dim buffer As Byte() = New Byte(10239) {}
            Dim progressPercent As Integer
            While (InlineAssignHelper(bytesRead, fs.Read(buffer, 0, buffer.Length))) <> 0
                Try
                    bytesSoFar += bytesRead
                    progressPercent = (bytesSoFar * 100) / fs.Length
                    Me.Invoke(New UpdateProgessCallback(AddressOf Me.updateprogress), "Chargement en cours : " & progressPercent.ToString & " %")
                    BackgroundWorker1.ReportProgress(progressPercent, Nothing)
                    If BackgroundWorker1.CancellationPending Then
                        BackgroundWorker1.ReportProgress(0)
                        fs.Dispose()
                        GC.Collect()
                        e.Cancel = True
                        Exit Sub
                    End If
                Catch ex As Exception
                    fs.Dispose()
                    GC.Collect()
                    Exit Sub
                End Try
            End While
            fs.Close()
        End Sub
     
        Private Delegate Sub UpdateProgessCallback(ByVal txt$)
        Private Sub updateprogress(ByVal txt$)
            Me.Text = txt
        End Sub
     
        Public Function InlineAssignHelper(Of T)(ByRef target As T, ByVal value As T) As T
            target = value
            Return value
        End Function
     
        Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
            If Not e.ProgressPercentage > 100 Then
                ProgressBar1.Value = e.ProgressPercentage
            End If
        End Sub
     
        Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
            If e.Cancelled Then
                MsgBox("Opération annulée !")
                Button1.Text = "Lancer"
                Me.ProgressBar1.Value = 0
                Me.Text = "ReadBigFile"
            Else
                MsgBox("Opération terminée !")
                Button1.Text = "Lancer"
            End If
            _InProgress = False
        End Sub
     
        Private Sub Frm_Main_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
            If _InProgress Then
                MsgBox("Veuillez attendre la fin du chargement ou annuler l'opération !")
                e.Cancel = True
            End If
        End Sub
     
    End Class

    NB : j'ai volontairement introduit certaine fonction ou composant pour montrer la base de leur utilisation:
    - le backgroundWorker (annulation de tache, etc...)
    - un délégué avec 1 argument
    - ne pas fermer l'appli lorsqu'un délégué de fenêtre principale a été invoqué.
    ...etc....

    La source :

    http://wallace87000.upd.fr/ReadBigFile.zip

  11. #11
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Merci beaucoup wallace1, c'est vraiment impressionnant ! Je ne pensais pas que le backgroundworker était adapté à ce type de programme, et je m'aperçois que c'est le cas, encore merci !

  12. #12
    Membre du Club
    Inscrit en
    Mai 2008
    Messages
    125
    Détails du profil
    Informations personnelles :
    Âge : 41

    Informations forums :
    Inscription : Mai 2008
    Messages : 125
    Points : 45
    Points
    45
    Par défaut
    Juste une petite question, est-il possible de récupérer les octets lus dans un tableau de bytes afin de pouvoir les traiter à la fin de la lecture ?

    Est-ce que ceci est possible avec :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    Dim dest As New MemoryStream()
    While (InlineAssignHelper(bytesRead, fs.Read(buffer4, 0, buffer4.Length))) <> 0
    Try
    bytesSoFar += bytesRead
    progressPercent = (bytesSoFar * 100) / fs.Length
    dest.Write(buffer4, 0, bytesRead)
    Merci wallace1

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [XPATH 1.0] Temps de lecture d'un "gros" fichier XML
    Par Ikki_2504 dans le forum XSL/XSLT/XPATH
    Réponses: 10
    Dernier message: 14/01/2011, 18h27
  2. [XML] Lecture d'assez gros fichiers XML
    Par jeronimo83 dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 19/02/2010, 18h26
  3. Optimiser lecture d'un gros fichier
    Par n8ken dans le forum Entrée/Sortie
    Réponses: 0
    Dernier message: 17/09/2009, 11h14
  4. Lecture d'un gros fichier (jusqu a 300 Mo)
    Par Tidus159 dans le forum Entrée/Sortie
    Réponses: 13
    Dernier message: 10/04/2009, 16h57
  5. Optimisation de la lecture de tres gros fichiers
    Par Lydie dans le forum C++Builder
    Réponses: 4
    Dernier message: 12/07/2004, 14h09

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo