Je pense avoir mis au point un moyen très efficace de lire de très gros fichiers ligne par ligne. S'il vous plaît dites-moi si vous connaissez un moyen meilleur/plus rapide ou voyez une marge d'amélioration. J'essaie de m'améliorer en codage, alors n'importe quel conseil serait Nice. J'espère que c'est quelque chose que d'autres personnes pourraient trouver utile, aussi.
Cela semble être quelque chose comme 8 fois plus rapide que d'utiliser l'entrée de ligne de mes tests.
'This function reads a file into a string. '
'I found this in the book Programming Excel with VBA and .NET. '
Public Function QuickRead(FName As String) As String
Dim I As Integer
Dim res As String
Dim l As Long
I = FreeFile
l = FileLen(FName)
res = Space(l)
Open FName For Binary Access Read As #I
Get #I, , res
Close I
QuickRead = res
End Function
'This function works like the Line Input statement'
Public Sub QRLineInput( _
ByRef strFileData As String, _
ByRef lngFilePosition As Long, _
ByRef strOutputString, _
ByRef blnEOF As Boolean _
)
On Error GoTo LastLine
strOutputString = Mid$(strFileData, lngFilePosition, _
InStr(lngFilePosition, strFileData, vbNewLine) - lngFilePosition)
lngFilePosition = InStr(lngFilePosition, strFileData, vbNewLine) + 2
Exit Sub
LastLine:
blnEOF = True
End Sub
Sub Test()
Dim strFilePathName As String: strFilePathName = "C:\Fld\File.txt"
Dim strFile As String
Dim lngPos As Long
Dim blnEOF As Boolean
Dim strFileLine As String
strFile = QuickRead(strFilePathName) & vbNewLine
lngPos = 1
Do Until blnEOF
Call QRLineInput(strFile, lngPos, strFileLine, blnEOF)
Loop
End Sub
Merci pour le conseil!
Vous pouvez utiliser Scripting.FileSystemObject pour effectuer cette opération. À partir de Référence :
La méthode ReadLine permet à un script de lire des lignes individuelles dans un fichier texte. Pour utiliser cette méthode, ouvrez le fichier texte, puis configurez une boucle Do Do continue jusqu'à ce que la propriété AtEndOfStream soit définie sur True. (Cela signifie simplement que vous avez atteint la fin du fichier.) Dans la boucle Do, appelez la méthode ReadLine, stockez le contenu de la première ligne dans une variable, puis effectuez une action. Lorsque le script effectue une boucle, il laisse automatiquement tomber une ligne et lit la deuxième ligne du fichier dans la variable. Cela continuera jusqu'à ce que chaque ligne ait été lue (ou jusqu'à ce que le script quitte spécifiquement la boucle).
Et un exemple rapide:
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("C:\FSO\ServerList.txt", 1)
Do Until objFile.AtEndOfStream
strLine = objFile.ReadLine
MsgBox strLine
Loop
objFile.Close
Mes deux centimes…
Il n’ya pas longtemps, j’avais besoin de lire de gros fichiers avec VBA et j’ai remarqué cette question. J'ai testé les trois approches permettant de lire les données d'un fichier afin de comparer sa vitesse et sa fiabilité pour une large gamme de tailles de fichiers et de longueurs de lignes. Les approches sont:
Line Input
instruction VBAGet
VBA pour l'ensemble du fichier, puis analyse de la chaîne lue comme décrit dans les publications iciChaque cas de test comprend trois étapes:
Comme vous pouvez le constater, l'étape 3 vérifie la vitesse réelle de lecture du fichier (comme indiqué dans la question), tandis que l'étape 2 vérifie l'intégrité de la lecture du fichier et simule donc les conditions réelles dans lesquelles l'analyse de chaîne est nécessaire.
Le tableau ci-dessous présente les résultats du test de vitesse de lecture de fichier. La taille du fichier est de 64 M octets pour tous les tests, et la longueur de la ligne de test varie de 2 octets (CRLF non compris) à 8 M octets.
CONCLUSION:
La saisie de ligne fonctionne bien pour les petits fichiers. Cependant, lorsque la taille des fichiers atteint environ 90k, Line Input saute partout et lit les données dans le mauvais ordre à partir du fichier source .
49k = ok
60k = ok
78k = ok
85k = ok
93k = error
101k = error
127k = error
156k = error
Leçon apprise - utilisez Scripting.FileSystemObject
Avec ce code, vous chargez le fichier en mémoire (en tant que grande chaîne), puis vous lisez cette chaîne ligne par ligne .
En utilisant Mid $ () et InStr (), vous lisez réellement le "fichier" deux fois, mais comme il est en mémoire, il n'y a pas de problème.
Je ne sais pas si VB's String a une longueur limitée (probablement pas), mais si les fichiers texte mesurent des centaines de mégaoctets, les performances risquent de chuter, en raison de l'utilisation de la mémoire virtuelle.
Je pense que, dans le cas d’un fichier volumineux, l’utilisation d’un flux serait beaucoup plus efficace, car la consommation de mémoire serait très faible.
Mais votre algorithme peut alterner entre l'utilisation d'un flux et le chargement de la totalité de la mémoire en fonction de la taille du fichier. Je ne serais pas surpris si l'un est seulement meilleur que l'autre sous certains critères.
Mon point de vue ... évidemment, vous devez faire quelque chose avec les données que vous avez lues. Si cela implique de l'écrire sur la feuille, ce sera terriblement lent avec une boucle For normale. Je suis arrivé à ce qui suit en me basant sur une récapitulation de certains éléments, plus de l’aide du site Web de Chip Pearson.
Lecture dans le fichier texte (en supposant que vous ne connaissiez pas la longueur de la plage qu'il va créer, seule la cellule de démarrage est donnée):
Public Sub ReadInPlainText(startCell As Range, Optional textfilename As Variant)
If IsMissing(textfilename) Then textfilename = Application.GetOpenFilename("All Files (*.*), *.*", , "Select Text File to Read")
If textfilename = "" Then Exit Sub
Dim filelength As Long
Dim filenumber As Integer
filenumber = FreeFile
filelength = filelen(textfilename)
Dim text As String
Dim textlines As Variant
Open textfilename For Binary Access Read As filenumber
text = Space(filelength)
Get #filenumber, , text
'split the file with vbcrlf
textlines = Split(text, vbCrLf)
'output to range
Dim outputRange As Range
Set outputRange = startCell
Set outputRange = outputRange.Resize(UBound(textlines), 1)
outputRange.Value = Application.Transpose(textlines)
Close filenumber
End Sub
Inversement, si vous avez besoin d'écrire une plage dans un fichier texte, cela le fait rapidement en une instruction d'impression (remarque: le type de fichier 'Ouvrir' ici est en mode texte, pas binaire ... contrairement à la routine de lecture ci-dessus).
Public Sub WriteRangeAsPlainText(ExportRange As Range, Optional textfilename As Variant)
If IsMissing(textfilename) Then textfilename = Application.GetSaveAsFilename(FileFilter:="Text Files (*.txt), *.txt")
If textfilename = "" Then Exit Sub
Dim filenumber As Integer
filenumber = FreeFile
Open textfilename For Output As filenumber
Dim textlines() As Variant, outputvar As Variant
textlines = Application.Transpose(ExportRange.Value)
outputvar = Join(textlines, vbCrLf)
Print #filenumber, outputvar
Close filenumber
End Sub
'vous pouvez modifier ci-dessus et lire le fichier complet en une fois .__, puis afficher chaque ligne comme indiqué ci-dessous
Option Explicit
Public Function QuickRead(FName As String) As Variant
Dim i As Integer
Dim res As String
Dim l As Long
Dim v As Variant
i = FreeFile
l = FileLen(FName)
res = Space(l)
Open FName For Binary Access Read As #i
Get #i, , res
Close i
'split the file with vbcrlf
QuickRead = Split(res, vbCrLf)
End Function
Sub Test()
' you can replace file for "c:\writename.txt to any file name you desire
Dim strFilePathName As String: strFilePathName = "C:\writename.txt"
Dim strFileLine As String
Dim v As Variant
Dim i As Long
v = QuickRead(strFilePathName)
For i = 0 To UBound(v)
MsgBox v(i)
Next
End Sub
Je voulais juste partager certains de mes résultats ...
J'ai des fichiers texte, qui proviennent apparemment d'un système Linux. Je n'ai donc qu'une vbLF
Chr(10)
à la fin de chaque ligne et pas vbCR
/Chr(13)
.
_/ Note 1:
- Cela signifiait que la méthode
Line Input
lirait dans le fichier entier au lieu d'une seule ligne à la fois.
De mes recherches en testant des fichiers de petite taille (152 Ko) et des fichiers volumineux (2778LB), à la fois sur le réseau et hors réseau, j'ai constaté ce qui suit:
Open FileName For Input: Line Input
était le le plus lent (Voir Note 1 ci-dessus)
Open FileName For Binary Access Read: Input
était le le plus rapide pour lire tout le fichier
FSO.OpenTextFile: ReadLine
était rapide , mais un peu plus lent que Binary Input
Note 2:
Si je devais juste vérifier l'en-tête du fichier (1-2 premières lignes) pour vérifier si j'avais le bon fichier/format, alors
FSO.OpenTextFile
était le le plus rapide, suivi de très près parBinary Input
.L'inconvénient avec le
Binary Input
est que vous devez savoir combien de caractères tu veux lire.- Sur les fichiers normaux,
Line Input
serait également un bon option également, mais je n’ai pas pu tester en raison deNote 1.
Note 3:
- De toute évidence, les fichiers sur le réseau présentaient la plus grande différence de vitesse de lecture. Ils ont également montré le plus grand avantage à lire le fichier une seconde fois (bien qu’il y ait certainement des mémoires tampons qui entrent en jeu ici).
Soyez prudent lorsque vous utilisez Application.Transpose avec un grand nombre de valeurs. Si vous transposez des valeurs dans une colonne, Excel suppose que vous supposez que vous les avez transposées à partir de lignes.
Limite max. Colonne <Limite max. Ligne et affiche uniquement les premières valeurs (Limite max. Colonne) et après cela sera "N/A"