Optimisation de code vb.net Excel vers txt
bonjour à tous,
voila, j'ai fais une petite appli qui merge les onglets d'une liste de fichiers excel à la structure identique dans des fichiers textes
xl1.feuil1 + xl2.feuil1 + ... => txt1
xl1.feuil2 + xl2.feuil2 + ... => txt2
xl1.feuil3 + xl2.feuil3 + ... => txt3
xl1.feuil4 + xl2.feuil4 + ... => txt4
le programme marche mais met environs 10h pour merger 200 fichiers de 3Mo!!
chaque feuille excel contient environ 8000 lignes et j'utilise un worksheet.range pour copier les données et un streamwriter.writeline pour les écrire dans le fichier texte.
je pense que le problème vient de la car il semblerais qu'il n'écrivent qu'une petite trentaine de ligne à la seconde!!!
voici mon code:
Code:
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 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
#Région "Processing"
Private Sub pXLMerger(ByVal strInputDir As String, ByVal stroutputDir As String)
'variables "classiques"
Dim iMaxSheet, iCountSheet, iCountRangeLines As Integer
Dim bFirstFile As Boolean
Dim strLastRangeCol, strLine As String
'variables "fichier"
Dim swTxt(4) As StreamWriter
Dim fiFile As IO.FileInfo
'variables "Excel"
Dim appXL As New Excel.Application
Dim xlsInputWorkBook As Excel.Workbook
Dim xlsInputWorkSheet As Excel.Worksheet
Dim xlsInputRangeData As Excel.Range
'afin de supprimer les entete de colonnes sur les fichiers suivant le premier,
'un booléen flag le premier fichier
bFirstFile = True
'initialisation des variables
strLastRangeCol = ""
iCountRangeLines = 0
'lancement d'Excel en background
appXL.Visible = False
'instanciation des StreamWriter et suppression des fichiers existant
For i = 1 To 4
'récupération des info des fichiers textes si existant
Dim fOutputFile As New FileInfo(stroutputDir & "_" & i & ".txt")
'suppression des fichiers existants
If fOutputFile.Exists Then fOutputFile.Delete()
'instanciation des flux d'ecritures
swTxt(i) = New StreamWriter(stroutputDir & "_" & i & ".txt", False)
Next
'info sur le répertoire contenant les fichiers
Dim fExploitFolderExistance As New IO.DirectoryInfo(strInputDir)
'liste des fichiers excel à 'merger'
Dim afiFileList As IO.FileInfo() = fExploitFolderExistance.GetFiles("*.xls")
'boucle de copie des données
For Each fiFile In afiFileList
'ouverture du fichier xls
xlsInputWorkBook = appXL.Workbooks.Open(fiFile.FullName)
'compte le nombre d'onglet du fichier
iMaxSheet = xlsInputWorkBook.Sheets().Count
'info pour la pgbar
iTotalProcessedFiles += 1
'boucle par feuille
For iCountSheet = 1 To iMaxSheet
'selection de la feuille à traiter
xlsInputWorkSheet = xlsInputWorkBook.Worksheets(iCountSheet)
'je n'ai pas besoin de copier le contenus des feuilles cachées (d'ailleurs le programme plante si j'essai de copier leur contenus)
If xlsInputWorkSheet.Visible = Excel.XlSheetVisibility.xlSheetVisible Then
'activation de la feuille
xlsInputWorkSheet.Activate()
'ici une sous-routine compte le nombre effectife de ligne et de colonne avec des données
'car une propriété telle que xlsInputWorkSheet.Rows.Count me donne 65536 soit le nombre max de lignes d'un fichier
'au total ces opérations prennent 2 ou 3 secondes par feuille
strLastRangeCol = fColCount(xlsInputWorkSheet)
iCountRangeLines = fRowCount(xlsInputWorkSheet)
'on verifie que la feuille n'est pas vide
'getcolumn me retourne "Z" si le nombre de colonne est = 0 ou 26 (a cause du modulo)
If Not ((strLastRangeCol = "Z") And (iCountRangeLines = 0)) Then
'selon si l'on est entrain de le premier fichier ou les suivants la copie
'ne commence pas à la même ligne
If bFirstFile = True Then
xlsInputRangeData = xlsInputWorkSheet.Range("A1", strLastRangeCol & iCountRangeLines)
Else
xlsInputRangeData = xlsInputWorkSheet.Range("A2", strLastRangeCol & iCountRangeLines)
End If
'maintenant on copie les ligne et c'est la que ca prend du temps
'je boucle sur chaque ligne du range
For i = 1 To xlsInputRangeData.Rows.Count
'initialisation de la chaine qui va recevoir la valeur de la ligne
strLine = ""
'ici le boucle sur chaque cellulle du range par colonne
For j = 1 To xlsInputRangeData.Columns.Count
'incrémentation de la chaine qui sera copiée dans le fichier texte
strLine += xlsInputRangeData(i, j).value & Chr(9)
Next
'copie de la chaine dans le fichier texte correspondant
swTxt(iCountSheet).WriteLine(strLine.Substring(0, strLine.Length - 1))
Next
End If
End If
Next iCountSheet
'si c'est le premier fichier qui vient d'etre traiter on change le flag
If bFirstFile = True Then bFirstFile = False
'une fois le fichier entierement traiter on le ferme
xlsInputWorkBook.Close()
Next
'une fois tous les fichiers traiter on fermer les flux d'ecriture un par un
For i = 1 To 4
swTxt(i).Close()
Next
'puis on ferme excel (ici ca ne semble pas marché car bien qu'aucune erreur ne remonte,
'excel.exe reste lister dans le gestionnaire des taches, une idée peut-etre?)
appXL.Quit()
End Sub
'une simple fonction qui revoie une lettre (ou une suite de lettre) quand on lui fournis un chiffre
Function GetColumn(ByVal aValue As Long) As String
If aValue Mod 26 = 0 Then
If aValue = 26 Or aValue = 0 Then
GetColumn = "Z"
Else
GetColumn = Chr(64 + (aValue \ 26 - 1)) & GetColumn(aValue Mod 26)
End If
Else
If aValue < 26 Then
GetColumn = Chr(64 + aValue)
Else
GetColumn = Chr(64 + (aValue \ 26)) & GetColumn(aValue Mod 26)
End If
End If
End Function
'une fonction qui compte le nombre de lignes effectives d'une feuille excel
Private Function fRowCount(ByRef xlWorkSheet As Excel.Worksheet) As Long
Dim bSheetEnd As Boolean
'flag pour la fin du fichier
'on peut s'en passer mais il permet de continuer de compter si il y a une ligne vide
bSheetEnd = False
For fRowCount = 1 To 65336
If xlWorkSheet.Range("A" & fRowCount).Value = "" Then
If bSheetEnd = False Then
bSheetEnd = True
Else
Exit For
End If
End If
Next
Return fRowCount - 2
End Function
'fonction qui compte le nombre effectif de colonne d'une feuille excel
Private Function fColCount(ByRef xlWorkSheet As Excel.Worksheet) As String
Dim bSheetEnd As Boolean
Dim iColCount As Integer
'idem fRowCount, permet de compte une colonne vide
bSheetEnd = False
For iColCount = 1 To 65336
If xlWorkSheet.Cells(1, iColCount).value = "" Then
If bSheetEnd = False Then
bSheetEnd = True
Else
Exit For
End If
End If
Next
Return GetColumn(iColCount - 2)
End Function
#End Region |
Code fonctionnel en fin de thread