Problème pour supprimer les espaces d'un fichier texte.

Résolu
cryptic Messages postés 7 Date d'inscription mercredi 23 août 2023 Statut Membre Dernière intervention 24 août 2023 - Modifié le 24 août 2023 à 15:14
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 - 25 août 2023 à 20:05

Bonjour

J'ai un problème un peu inusité avec la méthode TRIM(). J'ai un espace qui ne s'efface pas.

J'ai un fichier .txt (UTF-8) qui est généré par un programme maison dont je n'ai pas le code source. Le fichier généré ressemble à ceci (extrait, le fichier contient 29000 lignes):

Part Number,Dealer List Value
DC-13             ,12.49
DFE100/8 12V      ,522.38
DIAGNOSTIC        ,85.00

Après chaque "Part Number" il y a un certain nombre d'espace qui est différent selon la longueur de chaque numéro.

Afin de les enlever, j'utilise la méthode TRIM(). Ça fonctionne mais il me reste toujours 1 espace qui n'est pas supprimé. Le fichier généré ressemble à ceci une fois la méthode TRIM() utilisée.

DC-13 ,12.49
DFE100/8 12V ,522.38
DIAGNOSTIC ,85.00
DJ7023 ,12.51
DJ70322Z ,16.19

Ce qui est inusité c'est que si j'ouvre le fichier .txt (UTF-8), que j'ajoute et retire un charactère et que j'enregistre (UTF-8) le fichier, la méthode TRIM() fonctionne et retire tous les espaces.

J'ai aussi essayé avec la méthode REPLACE(" ", ""). Les espaces s'effacent, sauf une.

J'ai trouvé de l'information au sujet d'un espace nommé "non breaking space" ( ). 

J'ai essayé la méthode REPLACE(" ", "") mais ça ne fonctionne pas.

J'ai décodé les espaces dans le fichier original et j'obtiens le même charactère pour chaque espace.

u0020\u0020\u0020\u0020\u0020\u0020\u0020\u0020\

Voici mon code au complet.

Je construis un Datatable avec le fichier texte original (espaces inclus).

Je converti les données en fichier CSV et en enlevant les espaces (sauf une qui reste).

Si j'ouvre mon fichier texte sur l'ordinateur avant la conversion, l'espace s'efface, sinon elle reste là.

 Dim filepath As String = TextBox1.Text 'Emplacement du fichier
        Dim sr As New StreamReader(filepath)
        Dim f As File
        Dim fval As String()
        Dim dt As New DataTable
        Dim dr As DataRow

        sr = f.OpenText(filepath)

        fval = sr.ReadLine().Split(",")


'Construction du Datatable
        For i As Integer = 0 To fval.Length - 1
            dt.Columns.Add(New DataColumn(fval(i).ToString()))
        Next

        dr = dt.NewRow

        While sr.Peek() <> -1
            fval = sr.ReadLine().Split(",")
            dr = dt.NewRow
            For i As Integer = 0 To fval.Length - 1
                dr.Item(i) = fval(i).ToString()
            Next

            dt.Rows.Add(dr)
        End While

'Affichage du Datatable
        DataGridView1.DataSource = dt


'Conversion en CSV
        Dim headers = (From header As DataGridViewColumn In DataGridView1.Columns.Cast(Of DataGridViewColumn)()
                       Select header.HeaderText).ToArray
        Dim rows = From row As DataGridViewRow In DataGridView1.Rows.Cast(Of DataGridViewRow)()
                   Where Not row.IsNewRow
                   Select Array.ConvertAll(row.Cells.Cast(Of DataGridViewCell).ToArray, Function(c) If(c.Value IsNot Nothing, c.Value.ToString.Trim(), "")) 'Methode TRIM pour effacer les espaces


'Enregistrement du fichier
        Using sw As New IO.StreamWriter(TextBox5.Text + "\PB_csv.csv")

            For Each r In rows

                sw.WriteLine(String.Join(",", r))
            Next
            sw.Close()

        End Using

Vous avez une idée pourquoi cet espace ne s'efface pas et comment la supprimer ?

Pour le fichier texte original c'est ici https://filebin.net/3f3ipppohxpydaqm

Merci

8 réponses

Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
24 août 2023 à 15:59

Oui ça marche

        Dim leTexte As String = File.ReadAllText("PBtxt.Txt")
        Dim trim = Regex.Replace(leTexte, "\x00\s+", "")
        File.WriteAllText("Sortie.txt", trim)

PS c'est p'tet un détail, mais y'a pas de retour à la ligne à la fin 


1
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
24 août 2023 à 16:05

Par contre, si tu fais "bêtement" comme ça tu vas perdre du temps.

Soit, tu fais tout le fichier à la lecture (comme dans mon exemple) et après, tu traites le string, un split sur CRLF va te donner un tableau ligne par ligne, tu pourras alimenter ton chargement depuis ce tableau au lieu de lire le streamreader ligne par ligne.

Ou alors, tu appliques le replace à l'écriture à la place de faire ton Trim.

Mais ouvrir le fichier, le traiter complétement et le réécrire (comme mon exemple) serait une perte de temps, d'autant que tu le rouvrirais aussitôt.

0
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
24 août 2023 à 15:49

Tout d'abord, le caractère c'est \u0020, et pas u0020\.

\u, c'est pour Unicode.

Quand j'ouvre ton fichier avec notepad++, en affichant les caractères invisibles, on voit un NUL avant les espaces (points oranges)

Donc le problème réside là.

A priori, NUL, c'est \00 (ou \u0000), mais il faut vérifier.

Je l'ouvre avec XVI32 (aussi moche qu'efficace !) et après DC-13, j'ai bien 00.

 Et pareil pour les autres.

Tu peux donc remplacer tous les caractères \0 par rien, puis faire ton Trim.

Je vais essayer si on peut le faire d'un coup avec une regex.


0
cryptic Messages postés 7 Date d'inscription mercredi 23 août 2023 Statut Membre Dernière intervention 24 août 2023 1
24 août 2023 à 16:12

Merci beaucoup encore pour ton aide Whismeril. Ton premier commentaire m'a donné la piste pour corriger le code.

J'ai remplacé

Select Array.ConvertAll(row.Cells.Cast(Of DataGridViewCell).ToArray, Function(c) If(c.Value IsNot Nothing, c.Value.ToString.Trim(), ""))

Par

Select Array.ConvertAll(row.Cells.Cast(Of DataGridViewCell).ToArray, Function(c) If(c.Value IsNot Nothing, c.Value.ToString.Replace(vbNullChar, "").Trim(), ""))

Et ça fonctionne !

0
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
24 août 2023 à 16:27

Certes.

Mais typiquement c'est une mauvaise utilisation du datagridview.

La manipulation des données devrait être faite dans la source de données, ton datatable ici.

Et ensuite juste réactualiser l'affichage.

Tous les cast que tu es obligé de faire sont très gourmands en ressources et en temps


0

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

Posez votre question
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
Modifié le 24 août 2023 à 22:15

Je me suis amusé à te montrer le gain de temps sans utiliser de datatable et avec le datagridview seulement en affichage (le moins de Cast possible)


D'abord, j'ai créé un fichier "origine" de 500k lignes et un fichier de mise à jour de 33k lignes" avec cette méthode

    ''' <summary>
    ''' Génére un fichier d'entrée, si le pas est 1, le prix varie de 0 à 80,
    ''' Si le pas est différent, alors le prix est toujours 99.99 ce qui servira de valeur de mise à jour
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <param name="NbLignes"></param>
    ''' <param name="Pas"></param>
    Private Sub GenereFichier(Filename As String, NbLignes As Integer, Pas As Integer)
        Dim liste As New List(Of String)
        Dim rnd As New Random()

        Dim null As String = Convert.ToChar(0).ToString()

        liste.Add("Part,Value")

        For i = 1 To NbLignes Step Pas
            liste.Add($"{$"toto{i}{null}",-15},{If(Pas = 1, $"{rnd.Next(0, 79)}.{rnd.Next(0, 99)}", "99.99")}")
        Next

        File.WriteAllLines(Filename, liste)
    End Sub

Y'a même le caractère null et le padding de la référence.

Que j'ai appelée 2 fois comme ça

GenereFichier("FichierOrigine.csv", 500000, 1)
GenereFichier("MiseAJour.csv", 500000, 15)


Une fois fait, j'ai écrit un code qui

  • ouvre le fichier d'origine et le charge dans un dico (le prix est casté en double, ça prend forcément un peu de temps, mais si tu veux faire des calculs, ben c'est mieux)
  • met à jour le dico avec le second fichier
  • en fait une liste d'une classe écrite pour l'occasion
  • enregistre la liste dans un 3eme fichier pour ne pas abimer mes belles créations
  • l'affiche sur le datagridview
  • et indique le temps de traitement
    ''' <summary>
    ''' Test avec un dico et traitement du fichier entier avec la regex
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <returns></returns>
    Private Function CreerDico(Filename As String) As Dictionary(Of String, Double)
        Dim fichier As String = File.ReadAllText(Filename)
        Dim trim = Regex.Replace(fichier, "\x00\s+", "")

        Dim res As New Dictionary(Of String, Double)

        Dim lignes As String() = trim.Split(vbCrLf, StringSplitOptions.RemoveEmptyEntries)

        For Each l As String In lignes.Skip(1)
            Dim datas As String() = l.Split(",")
            res.Add(datas(0), Convert.ToDouble(datas(1), CultureInfo.InvariantCulture))
        Next

        Return res

    End Function

    ''' <summary>
    ''' Charge le second fichier et met à jour le dictionnaire
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <param name="Dico"></param>
    Private Sub MajDico(Filename As String, ByRef Dico As Dictionary(Of String, Double))
        Dim lignes As String() = File.ReadAllLines(Filename)
        Dim maRegex As New Regex("\x00\s+")

        For Each l As String In lignes.Skip(1)
            Dim datas As String() = l.Split(",")
            Dim key As String = maRegex.Replace(datas(0), "")
            Dico(key) = Convert.ToDouble(datas(1), CultureInfo.InvariantCulture)
        Next
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim depart As DateTime = DateTime.Now
        Dim intermediaire As DateTime
        Dim fin As DateTime

        'lire le fichier d'origine sous la forme d'un dictionnaire
        Dim dico As Dictionary(Of String, Double) = CreerDico("FichierOrigine.csv")

        'Faire la mise à jour du dictionnaire avec le second fichier
        MajDico("MiseAJour.csv", dico)

        'convertir en liste de DatasCryptic pour le binding
        Dim liste As List(Of DatasCryptic) = dico.Select(Function(x) New DatasCryptic With
            {
            .Part = x.Key,
            .Value = x.Value
             }).ToList()

        'Export du fichier mis à jour
        File.WriteAllText("Fichier de sortie.txt", $"Part,Value{vbCrLf}{String.Join(vbCrLf, liste.Select(Function(d) $"{d.Part},{d.Value}"))}")

        intermediaire = DateTime.Now

        'binding
        DataGridView1.DataSource = liste

        fin = DateTime.Now

        TextBox1.Text = $"Durée : {(fin - depart)}{vbCrLf}Dont affichage : {fin - intermediaire}"
    End Sub


Et la classe

Public Class DatasCryptic
    Public Property Part As String
    Public Property Value As Double
End Class

Et ça donne ça compilé en debug (même pas en release), et sans avoir cherché à particulièrement optimiser.

1 seconde après le clic sur le bouton.

J'ai un Ryzen 7, 1.8Ghz et 16 Go de RAM, c'est pas mal, mais pas un super calculateur non plus. 

Je pense donc que chez toi aussi le gain serait de cet ordre.


0
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
Modifié le 25 août 2023 à 10:05

Bonjour, je continue à m'amuser.


La conversion du dico en liste est forcément un peu chronophage.

Mais d'un autre coté, accéder directement à la bonne valeur grâce à la clé fait gagner un temps considérable par rapport à une recherche.


J'ai donc essayé, dans un premier temps avec un liste triée.

    ''' <summary>
    ''' Test avec une liste et traitement du fichier entier avec la regex
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <returns></returns>
    Private Function CreerListe(Filename As String) As List(Of DatasCryptic)
        Dim fichier As String = File.ReadAllText(Filename)
        Dim trim = Regex.Replace(fichier, "\x00\s+", "")

        Dim res As New List(Of DatasCryptic)

        Dim lignes As String() = trim.Split(vbCrLf, StringSplitOptions.RemoveEmptyEntries)

        For Each l As String In lignes.Skip(1)
            Dim datas As String() = l.Split(",")
            res.Add(New DatasCryptic With
                {
                .Part = datas(0),
                .Value = Convert.ToDouble(datas(1), CultureInfo.InvariantCulture)
                })
        Next

        Return res

    End Function

    ''' <summary>
    ''' Charge le second fichier et met à jour la Liste, la liste doit être triée
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <param name="Liste"></param>
    Private Sub MajListeTriee(Filename As String, ByRef Liste As List(Of DatasCryptic))
        Dim maj As List(Of DatasCryptic) = CreerListe(Filename)
        Dim indexMaj As Integer = 0
        Dim m As DatasCryptic = maj(indexMaj)

        For i As Integer = 0 To Liste.Count - 1
            If Liste(i).Part = m.Part Then
                'on echange les datas dans la liste
                Liste(i) = m
                indexMaj += 1
                If indexMaj = maj.Count Then
                    'c'est fini, pas la peine de continuer à boucler sur Liste
                    Exit For
                Else
                    'on prend la valeur à mettre à jour suivante
                    m = maj(indexMaj)
                End If
            End If
        Next

    End Sub

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
        Dim depart As DateTime = DateTime.Now
        Dim intermediaire As DateTime
        Dim fin As DateTime

        'lire le fichier d'origine sous la forme d'un dictionnaire
        Dim liste As List(Of DatasCryptic) = CreerListe("FichierOrigine.csv")

        'Faire la mise à jour du dictionnaire avec le second fichier
        MajListeTriee("MiseAJour.csv", liste)

        'Export du fichier mis à jour
        File.WriteAllText("Fichier de sortie.txt", $"Part,Value{vbCrLf}{String.Join(vbCrLf, liste.Select(Function(d) $"{d.Part},{d.Value}"))}")

        intermediaire = DateTime.Now

        'binding
        DataGridView1.DataSource = liste

        fin = DateTime.Now

        TextBox1.Text = $"Durée : {(fin - depart)}{vbCrLf}Dont affichage : {fin - intermediaire}"
    End Sub
End Class

Là encore, j'ai plus ou moins une seconde.

Donc le "temps perdu" dans le for est plus ou moins compensé par le fait qu'on ne convertit plus un dico en listes.

Mais ce code ne marchera pas si la liste n'est pas triée, alors que le dico si. Et aucun des 2 ne sait gérer une nouvelle valeur dans le fichier de mise à jour.


0
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
25 août 2023 à 09:54

Et aucun des 2 ne sait gérer une nouvelle valeur dans le fichier de mise à jour.

Ha autant pour moi, le dico ajoute une valeur s'il tombe sur une clé inconnue (alors peut-être une différence avec le framework 6 ici utilisé et le 4.8 dont j'ai plus l'habitude ou erreur de ma part...).

Donc le dico sait gérer les nouvelles valeurs, mais ne les trie pas, elles sont ajoutées à la fin

0
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
25 août 2023 à 10:55

Pour une liste non triée (et donc des fichiers non triés).

J'ai d'abord dû générer 2 fichiers en bazar.

J'ai donc modifié ma méthode de création.

Elle utilise une méthode de mélange "magique" que j'ai péché il y a longtemps sur le net (et donc je ne sais plus où) en triant par une valeur aléatoire. Mais random n'est pas assez aléatoire, alors le gars avait eu l'idée de génie de générer un GUID.

Par contre, à la fin, pour que ce soit lisible et vérifiable, il faut pouvoir trier la collection.

Or, dans l'ordre de tri en string "toto2" arrive après "toto10", j'ai donc aussi modifié pour que "toto2" devienne "toto02"

    ''' <summary>
    ''' Génére un fichier d'entrée, si le pas est 1, le prix varie de 0 à 80,
    ''' Si le pas est différent, alors le prix est toujours 99.99 ce qui servira de valeur de mise à jour
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <param name="NbLignes"></param>
    ''' <param name="Pas"></param>
    Private Sub GenereFichier(Filename As String, NbLignes As Integer, Pas As Integer)
        Dim liste As New List(Of String)
        Dim entete As New List(Of String) From {"Part,Value"}
        Dim rnd As New Random()

        Dim null As String = Convert.ToChar(0).ToString()

        Dim paddNumero As New String("0"c, NbLignes.ToString().Length) '1 deviendra 001 si NbLignes est un nombre à 3 chiffres

        For i = 1 To NbLignes Step Pas
            liste.Add($"{$"toto{i.ToString(paddNumero)}{null}",-15},{If(Pas = 1, $"{rnd.Next(0, 79)}.{rnd.Next(0, 99)}", "99.99")}")
        Next

        'trie avec un aléa encore plus aléatoire que random
        Dim melange = liste.OrderBy(Function(x) Guid.NewGuid())

        File.WriteAllLines(Filename, entete.Concat(melange))
    End Sub

Et ça m'a fait 2 fichiers encore plus beaux que les précédents ;).

Pour l'instant, je n'ai pas ajouté de valeurs inconnues, donc en première intention et vu que mes tests précédents m'ont prouvé que la méthode la plus rapide c'est avec les listes triées, ben j'ai juste trié les listes en plus du traitement précédent.

    ''' <summary>
    ''' Charge le second fichier, tri les listes et met à jour la Liste
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <param name="Liste"></param>
    Private Sub MajListePasTriee(Filename As String, ByRef Liste As List(Of DatasCryptic))
        Dim maj As List(Of DatasCryptic) = CreerListe(Filename).OrderBy(Function(x) x.Part).ToList()
        Dim indexMaj As Integer = 0
        Dim m As DatasCryptic = maj(indexMaj)

        Liste = Liste.OrderBy(Function(x) x.Part).ToList()

        For i As Integer = 0 To Liste.Count - 1
            If Liste(i).Part = m.Part Then
                'on echange les datas dans la liste
                Liste(i) = m
                indexMaj += 1
                If indexMaj = maj.Count Then
                    'c'est fini, pas la peine de continuer à boucler sur Liste
                    Exit For
                Else
                    'on prend la valeur à mettre à jour suivante
                    m = maj(indexMaj)
                End If
            End If
        Next

    End Sub

Entre 2 et 3 secondes. Ce qui n'est pas mal du tout.

En effet, les fonctions de tri sont assez longues, car elles itèrent de nombreuses fois la collection pour tout ranger dans l'ordre.

Mais si j'ai une nouvelle valeur dans le fichier de mise à jour, c'est mort, la boucle va aller jusqu'à la fin de la liste principale et sortir.

Pas d'ajout de la nouvelle valeur (ce qui n'est pas bien) mais surtout pas de correction des données située après cette nouvelle valeur dans la liste de mise à jour triée => régression.

Je testerai un truc à base while et d'inférieur plus tard dans la journée, j'ai à faire maintenant.


0
Whismeril Messages postés 19076 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 27 juin 2024 658
25 août 2023 à 20:05

Et enfin

Cette méthode trie, ajoute ce qui va avant la liste principale, met à jour ce qui existe, insère ce qu'il manque au milieu, au bon endroit et ajoute tout ce qui va après.

J'ai du créé un fichier d'origine dans lequel il manque aléatoirement de valeurs en cours (au final 6364 lignes).

Et un fichier de mise à jour avec ces 6364 valeurs, 1761 valeurs avant (aléatoire), 3151 (choisis un peu au pif) valeurs après, et 25391 valeurs à mettre à jour.


Au début, je crée une variable log, si elle vaut true, ça écrit plusieurs fichiers permettant de faire de vérification (telle valeur est censée être avant, telle autre insérée au milieu, etc...)

Mais c'est 3 à 4 fois plus long.

Pour qu'elle fonctionne, il faudra ajouter ces 3 lignes dans la classe DatasCryptic

    Public Overrides Function ToString() As String
        Return $"{Part} : {Value}"
    End Function
    ''' <summary>
    ''' Charge le second fichier, tri les listes et met à jour la Liste
    ''' Il peut y avoir des nouvelles valeurs
    ''' </summary>
    ''' <param name="Filename"></param>
    ''' <param name="Liste"></param>
    Private Sub MajListePasTrieeEtNouvellesValeurs(Filename As String, ByRef Liste As List(Of DatasCryptic))
        Dim log As Boolean = False 'si true, loggue les valeurs avant, insérées, mises à jour et après dans des fichiers dédiés, tu pourras si tu le veux faire des vérifications, mais c'est beaucoup plus long

        Dim maj As List(Of DatasCryptic) = CreerListe(Filename).OrderBy(Function(x) x.Part).ToList()
        Dim indexMaj As Integer = 0
        Dim m As DatasCryptic = maj(indexMaj)

        Liste = Liste.OrderBy(Function(x) x.Part).ToList()
        Dim i As Integer = 0

        'on commence par voir si des nouvelles valeurs existent avant le début de la liste principale
        While Liste(i).Part.CompareTo(m.Part) = 1
            indexMaj += 1
            If indexMaj = maj.Count Then
                'c'est fini, pas la peine de continuer à boucler sur Liste
                Exit While
            Else
                'on prend la valeur à mettre à jour suivante
                m = maj(indexMaj)
            End If
        End While
        Liste.InsertRange(0, maj.Take(indexMaj))

        If log Then
            'pour vérifier qu'il fait bien le job
            File.WriteAllLines("ValeursAvant.csv", maj.Take(indexMaj).Select(Function(x) x.ToString()))
        End If

        i = indexMaj

        If log Then
            'pour vérifier qu'il fait bien le job
            File.WriteAllText("ValeursMAJ.csv", "")
            File.WriteAllText("ValeursInsérées.csv", "")
        End If


        'on partcours ensuite la liste principale à la recherche de mise à jour et d'ajout
        Do
            Select Case Liste(i).Part.CompareTo(m.Part)
                Case -1
                    'c'est "inférieur" on ppasse à la valeur suite
                    i += 1

                    'repart directement au début de la boucle Do
                    Continue Do

                Case 0
                    'on met à jour la valeur existante
                    Liste(i) = m

                    If log Then
                        'pour vérifier qu'il fait bien le job
                        File.AppendAllText("ValeursMAJ.csv", $"{m.ToString()}{vbCrLf}")
                    End If


                Case 1
                    'cette valeur est manquante, il faut donc l'inserer ici.
                    Liste.Insert(i, m)

                    If log Then
                        'pour vérifier qu'il fait bien le job
                        File.AppendAllText("ValeursInsérées.csv", $"{m.ToString()}{vbCrLf}")
                    End If

            End Select

            'on passe à la valeur suivante dans la liste des valeurs à mettre à jour
            indexMaj += 1
            If indexMaj = maj.Count Then
                'c'est fini, pas la peine de continuer à boucler sur Liste
                Exit Do
            Else
                'on prend la valeur à mettre à jour suivante
                m = maj(indexMaj)
            End If

            i += 1
        Loop While i < Liste.Count

        'enfin, on vérifie qu'il ne reste pas des valeurs à ajouter après la fin de la liste principale
        If indexMaj < maj.Count Then
            Liste.AddRange(maj.Skip(indexMaj))

            If log Then
                'pour vérifier qu'il fait bien le job
                File.WriteAllLines("ValeursAprès.csv", maj.Skip(indexMaj).Select(Function(x) x.ToString()))
            End If
        End If

    End Sub


Voilà, j'ai testé tout ça d'abord et avant tout parce que ça m'a amusé de me confronter à une quantité de données importantes (j'en ai parfois bien plus au travail).

Mais aussi, pour te faire prendre conscience de quelques points

  • ne pas utiliser les contrôles comme source de données, tu avais un datatable et tu prenais les valeurs dans le datagridview, très chronophage. En plus, si tu dois faire des calculs sur tes prix, ben avec des doubles, c'est immédiat, alors que caster le contenu d'une cell prend du temps à écrire et à exécuter
  • Linq c'est top, et tu sembles bien le maitriser, mais enchainer les requêtes multiplie les boucles. Du coup, avec une quantité de données importante, c'est long (quand j'ai appliqué le même principe que toi avec le except et le merge, je suis arrivé à 20 secondes ! ). Faire en sorte qu'une seule boucle fasse tout le travail, même si de base cette boucle est moins rapide que Linq, peut au final être bien plus rapide.
  • Dans ton code, tu ne profites pas vraiment des avantages du Binding, tu peux lire cet article pour avoir un aperçu plus étoffe https://codes-sources.commentcamarche.net/source/100588-utilisation-du-binding-a-travers-l-objet-data-binding-source

0
Rejoignez-nous