Große CSV einlesen

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

 

move.l

Betreff: Große CSV einlesen

BeitragSo, Feb 26, 2012 10:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo zusammen,

ich möchte eine CSV-Datei mit ca. 10.000 Zeilen und pro Zeile ca. 30 Werte einlesen.
Im Moment versuche ich das mit einer Funktion die ich auf blitzbasic.com gefunden habe.
Leider ist diese Funktion für die Größe einfach viel zu langsam.
Hat hier evtl. jemand eine Idee wie man das Ganze beschleunigen kann oder gänzlich alternative
Ideen?

Hinzukommt, daß ReadLine ebenfalls recht langsam zu sein scheint.

Vielen Dank.

Code: [AUSKLAPPEN]

Function readCSV:String[]( csvline:String , delimeter:Int= 59 )
   Local stringarray:String[1]
   Local word:String   
   Local letter:Int
   Local L = Len(csvline)
   If L=0 Then Return Null
   
      
   For Local d:Int = 0 To L-1
      
      If csvline[d] = delimeter   ' default = comma ' , '
         stringarray = stringarray[..Len(stringarray)+1]   ' resize the array to add another character
         word$ = Null
         letter = 0
      Else
            word$ = word+Chr(csvline[d])
            stringarray[Len(stringarray)-1] = word
            letter:+1
      EndIf
      
   Next
   Return stringarray
End Function

Noobody

BeitragSo, Feb 26, 2012 11:24
Antworten mit Zitat
Benutzer-Profile anzeigen
BlitzMax: [AUSKLAPPEN]
Function readCSV:String[]( csvline:String , delimeter:Int= 59 ) 
Return csvline.Split(Chr(delimeter))
End Function


In deiner ursprünglichen Funktion wird Buchstabe für Buchstabe zum String word hinzugefügt (und ggf. auf "" zurückgesetzt). Das bedeutet, dass ein String ständig vergrössert werden muss für jeden einzelnen Buchstaben in deiner CSV-Datei - das sind je nach dem sehr viele Razz Die hauseigene Split Methode sollte da hoffentlich schneller arbeiten
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

move.l

BeitragSo, Feb 26, 2012 12:19
Antworten mit Zitat
Benutzer-Profile anzeigen
Leider erweist sich "ReadLine" ebenfalls als große Bremse.
Ich habe eine Datei mit ca. 10.000 Zeilen einfach per ReadLine einlesen lassen, ohne irgendwas damit zu machen.
Dauer ca. 30 Sekunden, das wäre leider nicht akzeptabel.
Bevor ich hier weitermache, muss ich hierfür erstmal eine Lösung finden.

ZEVS

BeitragSo, Feb 26, 2012 12:28
Antworten mit Zitat
Benutzer-Profile anzeigen
Es gibt in meinen Augen nur eine schnelle Methode, einen String zu parsen: Einmal durchgehen:
BlitzMax: [AUSKLAPPEN]
Function readCSV:TList(str$)
Local list:TList = New TList
Local pos% = 0
For Local i%=0 Until str.length
Local c% = str[i]
If c = 44 Or c = 10 Then
list.AddLast str[pos..i]
pos = i+1
EndIf
Next
list.AddLast str[pos..str.length]
Return list
End Function

Local csv:TList = readCSV(LoadText("file.csv"))

Wenn dir Arrays lieber sind, würde ich die Liste konvertieren. Alternativ kannst du die Arraygröße auch immer verdoppeln. Es ist jedenfalls sinnlos, für jeden neuen Eintrag das Array zu vergrößern.

ZEVS
 

move.l

BeitragDi, Feb 28, 2012 22:22
Antworten mit Zitat
Benutzer-Profile anzeigen
Erstmal vielen Dank für die Hinweise, hat schonmal geholfen Smile

Leider erweist sich als größtes Problem "AddGadgetItem".
Auf dieser Basis: https://www.blitzforum.de/foru...hp?t=20102 wollte
ich eine Liste mit ca. 10.000 Zeilen darstellen.
Funktioniert auch alles, nur benötigt "AddGadgetItem" ca. 75 Sekunden Sad

Midimaster

BeitragMi, Feb 29, 2012 1:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Vier Gedanken von mir dazu:
1.
Das Lesen von 10.000.000 Byte in eine Bank geht z.B. über ReadBytes in 1.3sec. Vielleicht ist das ein sinnvoller Ansatz. Dort in der Bank müßte man dann das Trennen erledigen.

2.
kein User benötigt die 10.000 Einträge sofort. Man könnte also noch laden, während man bereits das Gadgat anzeigt. Bis der User den Schwindel bemerkt... ist alles da.

3.
Vielleicht sind 10.000 Einträge auch für den User gar nicht mehr handlebar? Wie soll er da noch den Überblick behalten. Teil es ihm auf und löse so das Problem der langen Ladezeit des AddGadgetItem.

4.
Ich hab mal in einem Thread hier oder auf der englischen Seite etwas darüber gelesen, dass man den Gadget verbieten kann, Events zu feuern. Das tun sie bei jedem neu hinzukommenden Eintrag. Unterbindest Du das, ist das Laden möglicherweise 100x schneller.
Gewinner des BCC #53 mit "Gitarrist vs Fussballer" http://www.midimaster.de/downl...ssball.exe
 

move.l

BeitragMi, Feb 29, 2012 10:04
Antworten mit Zitat
Benutzer-Profile anzeigen
Midimaster hat Folgendes geschrieben:
Vier Gedanken von mir dazu:
1.
Das Lesen von 10.000.000 Byte in eine Bank geht z.B. über ReadBytes in 1.3sec. Vielleicht ist das ein sinnvoller Ansatz. Dort in der Bank müßte man dann das Trennen erledigen.


Das Einlesen ist kein Problem mehr. Das ist schnell.

Midimaster hat Folgendes geschrieben:

2.
kein User benötigt die 10.000 Einträge sofort. Man könnte also noch laden, während man bereits das Gadgat anzeigt. Bis der User den Schwindel bemerkt... ist alles da.


Leider in diesem Fall doch, Benutzer öffnet das Programm und möchte sehr schnell ein paar Daten sehen,
Oben, Mitte, Unten und wieder schliessen.

Midimaster hat Folgendes geschrieben:

3.
Vielleicht sind 10.000 Einträge auch für den User gar nicht mehr handlebar? Wie soll er da noch den Überblick behalten. Teil es ihm auf und löse so das Problem der langen Ladezeit des AddGadgetItem.


Siehe Punkt 2


Midimaster hat Folgendes geschrieben:

4.
Ich hab mal in einem Thread hier oder auf der englischen Seite etwas darüber gelesen, dass man den Gadget verbieten kann, Events zu feuern. Das tun sie bei jedem neu hinzukommenden Eintrag. Unterbindest Du das, ist das Laden möglicherweise 100x schneller.


Das habe ich auch schon gelesen, es hat leider nichts gebracht.
http://www.blitzbasic.com/Comm...opic=55873

Aus dem gerade genannten Thread habe ich auch eine alternative Möglichkeit versucht und natürlich noch "Import MaxGui.Drivers" hinzugefügt, da ja sonst TGadget nicht funktionieren kann.
Dann bekomme ich für die Zeile: Code: [AUSKLAPPEN]
Global list:Int= CreateWindowExA( 0 ,Byte Ptr "LISTBOX".ToCString(),Byte Ptr "".ToCString(),WS_CHILD| WS_VISIBLE  ,0 ,0 ,200,200,window,0,GetModuleHandleA(0),Null)

nur die Fehlermeldung:

Code: [AUSKLAPPEN]
Compile Error

Unable to convert from 'Int' to 'Byte Ptr'



Code aus Thread:
Code: [AUSKLAPPEN]

SuperStrict

Extern "Win32"
   Function InvalidateRect(hWnd:Int, lpRect:Int, bErase:Byte)
End Extern

Local win1:TGadget=CreateWindow("AddGadgetItem Test", 0, 0, 300, 300)
Local win1hwnd:Int=QueryGadget(win1, QUERY_HWND)


Local window:Int=QueryGadget(win1, QUERY_HWND)

Global list:Int= CreateWindowExA( 0 ,Byte Ptr "LISTBOX".ToCString(),Byte Ptr "".ToCString(),WS_CHILD| WS_VISIBLE  ,0 ,0 ,200,200,window,0,GetModuleHandleA(0),Null)


SendMessageA(list, WM_SETREDRAW, False, 0)


Const LB_ADDSTRING:Int          = $180

Local timer:Int=MilliSecs()

Local testString:Byte Ptr = "8s6f987s6f987sa6d97d9sd6s6fsad96f9s987d6as9s876f9f8a7s".ToCString()

For Local i:Int=0 Until 4300
   
   
   SendMessageA(list, LB_ADDSTRING , Int testString, Int testString)
   
   
Next
Print "Time: "+(MilliSecs()-timer)

SendMessageA(list, WM_SETREDRAW, True, 0)
InvalidateRect(list, Null, True)

Repeat
   WaitEvent()
   Select EventID()
      Case EVENT_WINDOWCLOSE
         End
   End Select
Forever

End

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group