2009-09-28 10 views
0

J'ai du mal à accélérer le traitement d'un très gros fichier texte (~ 100 Meg ou plus). J'ai fait attention à être très diligent en utilisant les appels redim preserve, et pourtant la fonction prend encore 5 minutes ou plus pour fonctionner. Le fichier texte est essentiellement des sous-rapports que j'essaie d'analyser. J'ai seulement accès au gros fichier. Qu'est-ce qu'une personne à faire. VBA est-il si lent? Voici le code, l'objet "Report" est une classe que j'ai créée. La plupart des rapports sont juste quelques centaines de lignes, donc ce pourquoi je choisis 1000 pour le ubound:Traiter de gros fichiers texte rapidement avec VBA

Public Function GetPages(originalFilePath As String) As Collection 

Dim myReport    As report 
Dim reportPageCollection As Collection 
Dim startLine    As Long 
Dim endLine     As Long 
Dim fso      As FileSystemObject 
Dim file     As textStream 
Dim lineStr     As String 
Dim index     As Long 
Dim lines()     As String 

Set fso = New FileSystemObject 
Set reportPageCollection = New Collection 'initialize the collection 

Set file = fso.OpenTextFile(originalFilePath, ForReading) 

ReDim lines(0 To 1000) 
lineStr = file.ReadLine 'skip the first line so the loop doesnt add a blank report 
lines(0) = lineStr 
index = 1 

Do Until file.AtEndOfLine 'loop through from the startline to find the end line 

    lineStr = file.ReadLine 

      If lineStr Like "1JOBNAME:*" Then 'next report, so we want to return an array of the single line 

        'load this page into our report page collection for further processing 
        Set myReport = New report 
        myReport.setDataLines = lines() 'Fill in 'ReportPage' Array 

        reportPageCollection.Add myReport 'add our report to the collection 

        'set up array for new report 
        ReDim lines(0 To 1000) 
        index = 0 
        lines(index) = lineStr 
        index = index + 1 
      Else 

        '============================ store into array 
         If index = UBound(lines) Then 
          ReDim Preserve lines(0 To UBound(lines) + 1000) 
          lines(index) = lineStr 
          index = index + 1 
         Else 
          lines(index) = lineStr 
          index = index + 1 
         End If 
        '============================ 
      End If 
Loop 

file.Close 
Set fso = Nothing 
Set GetPages = reportPageCollection 

End Function

Toute aide est appréciée. Merci!

Répondre

4

Je viens d'attraper un fichier texte en ligne de 73 méga-octets à partir de mon lecteur C: \. Il a fallu 6 secondes pour lire le tout, ligne par ligne dans Excel VBA (ne faisant que lire). Donc, le problème de vitesse n'est pas forcément lié au fichier IO.

Quelques observations:

  • Je suis nerveux à l'idée d'avoir une variable nommée « fichier » lorsque le fichier est une classe dans le Runtime de script;
  • Do Until file.AtEndOfLine s'arrête presque immédiatement: vous êtes à la fin d'une ligne dès que vous en avez lu un. Je pense que vous voulez Do Until file.AtEndOfStream
  • le reste de votre code semble OK, bien que je passerions tous les trucs sur l'ajout de lignes à des tableaux dans une méthode sur votre report classe
  • est le fichier physiquement local? Ou lisez-vous à partir d'un lecteur réseau? Cela pourrait expliquer le problème. Si c'est le cas, pensez à lire le tout dans une chaîne et à le diviser. 100MB n'est pas vraiment énorme. 9 secondes pour le faire avec mon fichier 73MB.
  • Vous n'avez pas besoin de créer une variable de collection: getPages veut déjà être cette collection

donc votre code pourrait réduire à quelque chose comme ceci:

Public Function GetPages(originalFilePath As String) As Collection 

Dim myReport As report 

Set GetPages = New Collection 'initialize the collection' 

With New FileSystemObject ' no need to store an object' 

    With .OpenTextFile(originalFilePath, ForReading) ' ditto' 

     Set myReport = New report 
     myReport.AddLine .ReadLine 

     Do Until .AtEndOfStream 

      lineStr = file.ReadLine 

      If lineStr Like "1JOBNAME:*" Then 
       GetPages.Add myReport 
       Set myReport = New report 
      End If 

      myReport.AddLine lineStr ' all the array business happens here - much tidier' 

     Loop 
    End With ' TextStream goes out of scope & closes' 
End With ' FileSystemObject goes out of scope, disappears' 

End Function 

Y at-il là-bas qui aide ?

+0

le fichier est sorti sur un lecteur réseau, mais j'ai omis de mentionner que je le copie sur le lecteur local avant de commencer à le lire. Je vais essayer. Merci! – Fink

+0

a bien fonctionné! Pris <10 sec pour un fichier de 150 mégaoctets. Je ne sais pas trop pourquoi c'était si lent avant. Maintenant, pour ajuster les autres fonctions. – Fink

-4

VBA est-il si lent?

Oui. Essayez XLW, un wrapper C++ pour Excel.

0

Il y a quelques ajustements que vous pourriez faire, l'objet FSO est connu pour être plus lent que l'IO natif de VB. Mais je ne vois rien de vraiment haineux ici. Avant de passer à la micro-optimisation, permettez-moi de poser une question plus fondamentale ... Ces fichiers se trouveraient-ils sur un lecteur partagé ou sur un site ftp? Si c'est le cas, envisagez de les copier dans un dossier temporaire avant de les traiter.

+0

Quand vous dites "connu pour être plus lent", avez-vous des références pour cela? J'ai trouvé le contraire pour être vrai. –

+0

est un lecteur réseau partagé, mais je le copie sur la machine locale avant le traitement. – Fink

+0

@Mike Je n'ai pas de lien pratique pour vous, mais il est de notoriété publique (il suffit de google "fso is slow").Cela ne veut pas dire ne jamais utiliser le FSO. Le FSO économise beaucoup de temps lors du codage et sera parfaitement acceptable pour une grande variété de tâches. C'est juste si vous faites quelque chose de très très lourd, vous commencerez à remarquer une différence. Un exemple classique serait itérer tous les fichiers dans tous les répertoires sur le disque dur. Essayez FSO, puis essayez de le faire avec les fonctions natives (ou Win32 d'ailleurs). Vous remarquerez une différence substantielle. – Oorang

Questions connexes