Schneller Dateien verarbeiten??

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Schneller Dateien verarbeiten??

Beitrag von Blackskyliner »

Hi.
Ich schreibe derzeit ein Programm um eine CSV Datei zu parsen.
Solche CSV Dateien können gut und gerne über 30 Megabyte gehen.

Derzeit mache ich es so, dass ich folgenden Codeschnipsel nutze um diese Auszulesen, nach zu bearbeiten und dann in eine Datei schreiben

Code: Alles auswählen

If ReadFile(1, Dateien()\File)	
				
	CreateFile(2, Dateien()\TMPFile)
	Dateien()\UploadTemp = 1
	
	AddElement(TempFiles())
	TempFiles()\File = Dateien()\File+"_neu.csv"
	
	FileLength.q = Lof(1)

	
	While(Eof(1) = 0)
	
		FilePosition.q = Loc(1)
		SetGadgetText(#Text_2, "Fahrzeug"+#CRLF$+Str(FilePosition)+"/"+Str(FileLength))
		SetGadgetState(#ProgressBar_0, FilePosition * 100 / FileLength)
		
		FILE$ = ReadString(1)
		
		F01.s = ""
		F02.s = ""
		F03.s = ""
		F04.s = ""
		F05.s = ""
		F06.s = ""
		F07.s = ""
		F08.s = ""
		F09.s = ""
		F10.s = ""
		F11.s = ""
		F12.s = ""
		F13.s = ""
		
		Zeile.s = ""
		Zeile = FILE$
		F01.s = StringField(Zeile, 1, ";"); : Debug F01
		F02.s = StringField(Zeile, 2, ";"); : Debug F02
		F03.s = StringField(Zeile, 3, ";"); : Debug F03
		F04.s = StringField(Zeile, 4, ";"); : Debug F04
		F05.s = StringField(Zeile, 5, ";"); : Debug F05
		F06.s = StringField(Zeile, 6, ";"); : Debug F06
		F07.s = StringField(Zeile, 7, ";"); : Debug F07
		F08.s = StringField(Zeile, 8, ";"); : Debug F08
		F09.s = StringField(Zeile, 9, ";"); : Debug F09
		F10.s = StringField(Zeile, 10, ";"); : Debug F10
		F11.s = StringField(Zeile, 11, ";"); : Debug F11
		F12.s = StringField(Zeile, 12, ";"); : Debug F12
		F13.s = StringField(Zeile, 13, ";"); : Debug F13
					
               ;Hier sind dann noch Nahcbearbeitungen wie z.B. Quotes entfernen und div. Sonderzeichen

		If F01 <> Chr(34)+"F01"+Chr(34)
			NEWFILE$ = NEWFILE$ + F01 + ";" + F02 + ";" + F03 + ";" + F04 + ";" + F05 + ";" + F06 + ";" + F07 + ";" + F08 + ";" + F09 + ";" + F10 + ";" + F11 + ";" + F12 + ";" + F13 + #CRLF$

		EndIf
		
		
	Wend
	
	WriteStringN(2, NEWFILE$)
	
	CloseFile(2)
	CloseFile(1)
	SetGadgetState(#ProgressBar_1,GetGadgetState(#ProgressBar_1)+1)

EndIf
Der Code wird in einem Thread ausgeführt und die SetGadgetStates sind wichtig, da es ja bei großen Dateien sein kann dass es so aussieht als würde es hängen... Diese könnten, wie ich weiß meine Geschwindigkeitsbremse sein...

Wäre nett wenn mir jemand Tipps geben könnte, wie ich das optimieren kann so dass das Verarbeiten einer 3mB Datei nicht 2 Minuten und mehr dauert...



EDIT:
Hab mittlerweilen schon doppelte Geschwindigkeit erzielt indem ich das GadgetUpdate so hier mache:

Code: Alles auswählen

If ReadFile(1, Dateien()\File)	
				
	CreateFile(2, Dateien()\TMPFile)
	Dateien()\UploadTemp = 1
	
	AddElement(TempFiles())
	TempFiles()\File = Dateien()\File+"_neu.csv"
	
	FileLength.q = Lof(1)
	FilePosition.q = 0
	OldProzent = 0
	While(Eof(1) = 0)
		FilePosition = Loc(1)
		CurrProzent = FilePosition * 100 / FileLength
		
		If(OldProzent <> CurrProzent)
			
			SetGadgetText(#Text_2, "Fahrzeug"+#CRLF$+Str(FilePosition)+"/"+Str(FileLength))
			SetGadgetState(#ProgressBar_0, FilePosition * 100 / FileLength)
			OldProzent = CurrProzent
		EndIf
		FILE$ = ReadString(1)
		
		F01.s = ""
		F02.s = ""
		F03.s = ""
		F04.s = ""
		F05.s = ""
		F06.s = ""
		F07.s = ""
		F08.s = ""
		F09.s = ""
		F10.s = ""
		F11.s = ""
		F12.s = ""
		F13.s = ""
		
		Zeile.s = ""
		Zeile = FILE$
		F01.s = StringField(Zeile, 1, ";"); : Debug F01
		F02.s = StringField(Zeile, 2, ";"); : Debug F02
		F03.s = StringField(Zeile, 3, ";"); : Debug F03
		F04.s = StringField(Zeile, 4, ";"); : Debug F04
		F05.s = StringField(Zeile, 5, ";"); : Debug F05
		F06.s = StringField(Zeile, 6, ";"); : Debug F06
		F07.s = StringField(Zeile, 7, ";"); : Debug F07
		F08.s = StringField(Zeile, 8, ";"); : Debug F08
		F09.s = StringField(Zeile, 9, ";"); : Debug F09
		F10.s = StringField(Zeile, 10, ";"); : Debug F10
		F11.s = StringField(Zeile, 11, ";"); : Debug F11
		F12.s = StringField(Zeile, 12, ";"); : Debug F12
		F13.s = StringField(Zeile, 13, ";"); : Debug F13
					
		;Hier sind dann noch Nahcbearbeitungen wie z.B. Quotes entfernen und div. Sonderzeichen 

		If F01 <> Chr(34)+"F01"+Chr(34)
			NEWFILE$ = NEWFILE$ + F01 + ";" + F02 + ";" + F03 + ";" + F04 + ";" + F05 + ";" + F06 + ";" + F07 + ";" + F08 + ";" + F09 + ";" + F10 + ";" + F11 + ";" + F12 + ";" + F13 + #CRLF$

		EndIf
		
		
	Wend
	
	WriteStringN(2, NEWFILE$)
	
	CloseFile(2)
	CloseFile(1)
	SetGadgetState(#ProgressBar_1,GetGadgetState(#ProgressBar_1)+1)

EndIf
Nur ist das bei sehr großen Dateien immernoch zu langsam...
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Bisonte
Beiträge: 2468
Registriert: 01.04.2007 20:18

Beitrag von Bisonte »

wäre hilfreich ein oder 2 zeilen so einer csv zu sehen...

edit:

ah jetzt raff ich... also du hast wahrscheinlich nur das problem, das
deine gadgets stehenbleiben ?

dann könnte diese miniprozedur helfen. Da du ja mit setgadgetstate Events erzeugst, muessen die auch abgearbeitet werden.

also

Code: Alles auswählen

Procedure.i DoEvents()
  Define msg.MSG 
  If PeekMessage_(msg,0,0,0,1) 
    TranslateMessage_(msg) 
    DispatchMessage_(msg) 
  Else 
    ;Sleep_(1) 
  EndIf
EndProcedure
Eigentlich kann man diese immer nach den Setgadgetanweisungen aufrufen.
Ich benutze diese z.B. für einen Download mit Fortschrittsanzeige.
(daher kommt diese Prozedure auch ;) aus dem Codearchiv von Purearea)
Zuletzt geändert von Bisonte am 12.02.2009 12:32, insgesamt 1-mal geändert.
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Die ganz große Datei, die mit einem minimal veränderten Schnippsel geparst wird (Einfach mehr auslesungen für die einzelnen Felder)
sieht in etwa so aus:

Nur ohne die Leerzeilen zwischendrin, da spinnt mein Browser grade bissel.
Un davon dann halt mehrere zehntausende Zeilen...

(sind übrigens nur 2 Zeilen, wie gewünscht... halt bissle schlecht große Sachen hier im Forum zu posten :) )

Code: Alles auswählen


"A01";"A02";"A03";"A04";"A05";"A06";"A07";"A08";"A09";"A10";"A11";"A12";"A13";"A14";"A15";"A16";"A17";"A18";"A19";"A20";"A21";"A22"                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 

"10225561512";"N";"IrgendeinName";"Beschreibung";"Nochmehrbeschreibung";"Meist Leer";"bla";"blubb";"und";"so";"weiter";"und";"so";"fort";"halt";"ne";"";"";"";"";"";"CSV"    


EDIT:
Zu deinem Edit ;)

Nein die Gadgets funktionieren. Hab den Quellcode ja in einem Thread ausgelagert. Mein Problem ist, dass die ganze Dateiverarbeitung insgesammt zu langsam ist... Und wie man das schneller gestalten könnte.
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Bisonte
Beiträge: 2468
Registriert: 01.04.2007 20:18

Beitrag von Bisonte »

Ich mache das über 1 Linklist.

Lese das file ein (komplett) bearbeite das ganze und speicher dann wieder die linklist. braucht zwar mehr speicher, ist aber recht flink.
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Ich will ja nicht schnorren, aber hast du da mal einen kleinen Schnipsel für mich? <)

Bin schon etwas raus aus der PB Materie
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Bisonte
Beiträge: 2468
Registriert: 01.04.2007 20:18

Beitrag von Bisonte »

Blackskyliner hat geschrieben:Ich will ja nicht schnorren, aber hast du da mal einen kleinen Schnipsel für mich? <)

Bin schon etwas raus aus der PB Materie
bin schon dabei kleinen moment ;)
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
Bisonte
Beiträge: 2468
Registriert: 01.04.2007 20:18

Beitrag von Bisonte »

Code: Alles auswählen

Structure filestruct
  Line.s
EndStructure

Global NewList File.filestruct()

Procedure.i F_Read(Filename.s,Flag = #PB_Ascii)

  Protected Nr, Zeilen
  ClearList(File())
 
  Nr = ReadFile(#PB_Any,Filename)
 
  If Nr

    While Eof(Nr)=0

      AddElement(File())
      File()\Line = ReadString(Nr, Flag)   
   
    Wend

    CloseFile(Nr)
 
  Else
 
    ProcedureReturn 0
 
  EndIf

  ProcedureReturn ListSize(File())
EndProcedure 
Procedure.i F_WriteN(Filename.s, Flag.l=#PB_Ascii)

  Protected Nr, Zeilen
  
  Nr = CreateFile(#PB_Any,Filename)
    
  If Nr

    ForEach File()
    
      WriteStringN(Nr,File()\Line, Flag)
    
    Next 

    CloseFile(Nr)
    
    ProcedureReturn #True
    
  Else
  
    ProcedureReturn #False
  
  EndIf

EndProcedure

Procedure CSV_Convert(Filename.s)

Protected Tempfile.s = GetTemporaryDirectory() + GetFilePart(Filename)
Protected Zeilen

Zeilen = F_Read(Filename)

If Zeilen > 0

  ForEach File()

    ; hier wäre die bearbeitung der strings (zeilen)
  
  Next

  ; und wenn alles fertig ist, dann das ganze wieder speichern
  
  If F_WriteN(Tempfile)
    Debug "OK"
  Else
    Debug "Fehler beim schreiben."
  EndIf

EndIf

EndProcedure
ist jetzt allerdings nicht für Thread handling ausgelegt...

Edit: Ich doktor mit dem F_Read und F_WriteN mit html source und SQL Dumps (meist über 100MB) und sobald die erstmal im speicher sind ist die Geschwindigkeit halt je nach cpu ...
PureBasic 6.21 (Windows x86/x64) | Windows11 Pro x64 | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | GeForce RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Danke. :allright: Das ist relativ Egal, da ja nur ein Thread gestartet wird und der Main nicht auf diese Dateien zugreift.

Wenn ich noch Probleme oder Fragen hab werd ich mich bei dir melden.
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Benutzeravatar
Tafkadasom2k5
Beiträge: 1578
Registriert: 13.08.2005 14:31
Kontaktdaten:

Beitrag von Tafkadasom2k5 »

@Blackskyliner
Deine Optimierung des "SetGadgetState(#ProgressBar_0, FilePosition * 100 / FileLength)" ist schonmal ganz gut. Nächster Schritt wäre vielleicht, nur alle 5% eine Anzeige zu machen.
5/10er Schritte sollten die Geschwindigkeit nochmal ein wenig tunen.

Als nächstest, und da bin ich mir gerade nicht mehr sicher wie Pure sich hier verhält, solltest du mal an den Schritten des "Readfiles" arbeiten. In der Regel kann man einstellen, wie groß die Schritte sind, die pro "ReadString(1)" gemacht werden.

[nostalgiemode]Je nach Dateisystem etc pp kann man darüber noch eine gewisse Geschwindigkeit erzielen, zumindest konnte man 10-30% zu Dos-Zeiten da noch herauskitzeln. <) [/nostalgiemode]

Dann wäre da noch folgendes

Code: Alles auswählen

FILE$ = ReadString(1)
      
      F01.s = ""
      F02.s = ""
      F03.s = ""
      F04.s = ""
      F05.s = ""
      F06.s = ""
      F07.s = ""
      F08.s = ""
      F09.s = ""
      F10.s = ""
      F11.s = ""
      F12.s = ""
      F13.s = ""
      
      Zeile.s = ""
      Zeile = FILE$ 
Warum das Ganze?

Ich würde es so schreiben

Code: Alles auswählen

Zeile = ReadString(1)
Dabei ersparst du pure die gesame Stringarbeit. Sofern "FieldString" im nächsten Schritt nichts zurückgibt, so wieder doch so-oder-so der jeweilige String wieder auf #NUL gesetzt, oder?

Gr33tz
Tafkadasom2k5

Edit: Auf LinkedLists würde ich verzichten, wenns geht dann lieber mit nem Array, das kann die Geschwindigkeit je nach Benutzung auch nochmals steigern. Gut, kann auch Geschmackssache sein :wink: :allright:
OpenNetworkConnection() hat geschrieben:Versucht eine Verbindung mit dem angegebenen Server aufzubauen. 'ServerName$' kann eine IP-Adresse oder ein voller Name sein (z.B.: "127.0.0.1" oder "ftp.home.net").
php-freak hat geschrieben:Ich hab die IP von google auch ned rausgefunden!
Benutzeravatar
Blackskyliner
Beiträge: 532
Registriert: 28.07.2005 00:54
Wohnort: /home/Blackskyliner/

Beitrag von Blackskyliner »

Wollte es halt übersichtlich gestalten. =)

Ich integriere derzeit den Code von Bisonte, da es wirklich bei großen Dateien schneller klappt las meine Methode. :)


EDIT
Hab folgendes Problem mit dem Code von Bisonte

Hab das ganze jetzt umgeschrieben und nutze auch keine Threads mehr.
Nun habe ich aber ein Problem des Invalid Memory Access obwohl ich doch garnicht mehr mit Thread arbeite? Muss ich mir erst die Ganze Liste als Protected in die Funktion rein laden und dann bearbeiten oder wie muss ich jetzt vorgehen?

Code: Alles auswählen


If F_Read(Dateien()\File) > 0
					
					
	ResetList(ZwischenspeicherDatei())
	
	FileLength.q = ListSize(ZwischenspeicherDatei())
	FilePosition.q = 0
	OldProzent = 0
	
	ForEach ZwischenspeicherDatei()
		
		FilePosition = FilePosition + 1
		
		CurrProzent = FilePosition * 100 / FileLength
		
		If(OldProzent < CurrProzent)
			SetGadgetText(#Text_2, "Fahrzeug"+#CRLF$+Str(FilePosition)+"/"+Str(FileLength))
			SetGadgetState(#ProgressBar_0, FilePosition * 100 / FileLength)
			OldProzent = CurrProzent + 5
			
			DoEvents()
		EndIf
		
		
		FILE$ = ZwischenspeicherDatei()\Line
			
			Zeile = FILE$
			F01.s = StringField(Zeile, 1, ";"); : Debug F01
			F02.s = StringField(Zeile, 2, ";"); : Debug F02
		F03.s = StringField(Zeile, 3, ";"); : Debug F03
		F04.s = StringField(Zeile, 4, ";"); : Debug F04
		F05.s = StringField(Zeile, 5, ";"); : Debug F05
		F06.s = StringField(Zeile, 6, ";"); : Debug F06
		F07.s = StringField(Zeile, 7, ";"); : Debug F07
		F08.s = StringField(Zeile, 8, ";"); : Debug F08
		F09.s = StringField(Zeile, 9, ";"); : Debug F09
		F10.s = StringField(Zeile, 10, ";"); : Debug F10
		F11.s = StringField(Zeile, 11, ";"); : Debug F11
		F12.s = StringField(Zeile, 12, ";"); : Debug F12
		F13.s = StringField(Zeile, 13, ";"); : Debug F13
					


		If F01 <> Chr(34)+"F01"+Chr(34)
			NEWFILE$ = NEWFILE$ + F01 + ";" + F02 + ";" + F03 + ";" + F04 + ";" + F05 + ";" + F06 + ";" + F07 + ";" + F08 + ";" + F09 + ";" + F10 + ";" + F11 + ";" + F12 + ";" + F13 + #CRLF$
		EndIf
		
		ZwischenspeicherDatei()\Line = NEWFILE$ ; HIER TRITT DER ACCESS FEHLER AUF
	Next
	
	Dateien()\UploadTemp = 1
	F_WriteN(Dateien()\TMPFile)
	
	MessageRequester("Fertig", "Fahrzeuge fertig bearbeitet")

EndIf


Wenn du mir ein Beispiel mir Arrays gibst, kein Problem, damit hab ich hier in PB noch nie gearbeitet...
Keine meiner Antworten ist endgültig, es kann passieren, dass ich den so eben geposteten Beitrag noch mehrmals ändere, um Doppelposts zu umgehen.
_________________
Purebasic Windows 7 x64 & Linux (Ubuntu 10.04LTS) 4.50[x64|x86] Nutzer
_________________
Projekte: YAED - Yet another Event Dispatcher
Antworten