Textdatei in Array laden

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Textdatei in Array laden

Beitrag von NicTheQuick »

Ich habe eben den Thread gelesen und wollte auch mal meinen Senf dazu geben. Allerdings nicht wundern. Ich halte nichts von einer Nummerierung ab 1 in einem Array.
Eine Sache ist noch nicht implementiert, nämlich UTF-8. Da dort die Zeichenlänge in Byte unterschiedlich sein kann, ist es nicht ganz so leicht da durch zu rennen. Aber ich habe da schon eine Idee. Wichtig war für mich auch, dass alle drei Zeilenumbrüche erkannt werden, also CR, LF und CRLF.
Macht mal einen Speedtest. Hab da grad keine Lust zu. :D

///Edit:
Code etwas geändert, damit keine extra Structure mehr nötig ist.

Code: Alles auswählen

;Text2Array (PB 4.50 beta 2)
;von DrFalo, ts-soft, NicTheQuick, ...

EnableExplicit

Procedure Text2Array(Datei.s, Array TextZeile.s(1))
	Protected cLines.i, fileSize.i, stringFormat.i
	Protected hFile = ReadFile(#PB_Any, Datei)
	Protected *memBegin, *mem, i.i, *memEnd, *lineBegin, ca.a, cc.c
	Protected NewList lineBegins.i()
	
	If hFile
		stringFormat = ReadStringFormat(hFile)
		
		fileSize = Lof(hFile)
		If fileSize = 0 : ProcedureReturn : EndIf
		
		*memBegin = AllocateMemory(fileSize)
		If *memBegin
			ReadData(hFile, *memBegin, fileSize)
		EndIf
		CloseFile(hFile)
	EndIf
	
	If Not *memBegin : ProcedureReturn : EndIf
	*mem = *memBegin
	*memEnd = *mem + fileSize
	
	Select stringFormat
		Case #PB_Ascii
			Debug "ASCII"
			*lineBegin = *mem
			While *mem < *memEnd
				ca = PeekA(*mem)
				Select ca
					Case #CR
						PokeA(*mem, 0)
						If AddElement(lineBegins())
							lineBegins() = *lineBegin
						EndIf
						If PeekA(*mem + 1) = #LF : *mem + 1 : EndIf
						*lineBegin = *mem + 1
					
					Case #LF
						PokeA(*mem, 0)
						If AddElement(lineBegins())
							lineBegins() = *lineBegin
						EndIf
						*lineBegin = *mem + 1
				EndSelect
				*mem + 1
			Wend
			If *lineBegin < *memEnd
				If AddElement(lineBegins())
					lineBegins() = *lineBegin
				EndIf
			EndIf
		
		Case #PB_UTF8
			Debug "UTF8"
			;TODO
			
		Case #PB_Unicode
			Debug "UNICODE"
			*lineBegin = *mem
			While *mem < *memEnd
				cc = PeekC(*mem)
				Select cc
					Case #CR
						PokeC(*mem, 0)
						If AddElement(lineBegins())
							lineBegins() = *lineBegin
						EndIf
						If PeekC(*mem + 2) = #LF : *mem + 1 : EndIf
						*lineBegin = *mem + 2
					
					Case #LF
						PokeC(*mem, 0)
						If AddElement(lineBegins())
							lineBegins() = *lineBegin
						EndIf
						*lineBegin = *mem + 2
				EndSelect
				*mem + 2
			Wend
			If *lineBegin < *memEnd
				If AddElement(lineBegins())
					lineBegins() = *lineBegin
				EndIf
			EndIf
			
		Default
			ProcedureReturn
	EndSelect
	
	cLines = ListSize(lineBegins())
				
	ReDim TextZeile(cLines - 1)
	
	i = 0
	ForEach lineBegins()
		TextZeile(i) = PeekS(lineBegins(), -1, stringFormat)
		i + 1
	Next
	
	FreeMemory(*memBegin)
EndProcedure

Define.s Datei
Define A, time.i
Dim TextZeile.s(0)

Datei.s = OpenFileRequester("Datei auswählen...", "", "Text (.txt)|*.txt", 0)
If Datei
	
	time.i = ElapsedMilliseconds()
	Text2Array(Datei, TextZeile.s())
	time = ElapsedMilliseconds() - time
	
	MessageRequester("", "Zeit: " + Str(time) + " ms") ;28 ms
	
	Debug "Insgesamt " + Str(ArraySize(TextZeile()) + 1) + " Zeilen"
	Debug ""
	For A = 0 To ArraySize(TextZeile())
		If A = 200
			Debug "u.s.w."
			Break ; ab Zeile 10 abbrechen
		EndIf
		Debug "Zeile " + Str(A) + ":  " + TextZeile(A)
	Next A
	
EndIf
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: Textdatei in Array laden

Beitrag von rolaf »

NicTheQuick hat geschrieben:Macht mal einen Speedtest. Hab da grad keine Lust zu. :D
Gerade getestet, läuft auf meinem Rechner rund 9 mal langsamer als Variante 1. Hast also noch was mehr rausgeholt, aber dafür reichlich mehr Code und reichen tut es noch lange nicht .

Klarer Vorteil für Readstring, zumal man dort mit den Flags easy Ascii, Utf8 und Unicode umsetzen kann. :allright:
Manchmal setzt sich eben auch das Einfache durch. Ich schätze mal ReadString ist so gut optimiert das selbst der beste Zerhacker des Speichers nix mehr machen kann. :wink:
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
al90
Beiträge: 1103
Registriert: 06.01.2005 23:15
Kontaktdaten:

Re: Textdatei in Array laden

Beitrag von al90 »

NicTheQuick hat geschrieben:Ich halte nichts von einer Nummerierung ab 1 in einem Array.
Dem kann ich nur zustimmen. Zumal es schnell zu inkompatibelitäten kommen kann. Gadgets wie ListIcons u.s.w. beginnen eben alle mal bei '0'. :wink:
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Textdatei in Array laden

Beitrag von NicTheQuick »

Ich weiß zwar nicht wie du testest, aber das Ergebnis hat mich gewundert und ich habe selbst mal getestet.

Ergebnis bei einer 1,3 MB Datei mit 31780 Zeilen unter meinem System nach mehreren Tests wegen Dateicachings:

Deine Variante 1: mehrmals genau 32 ms
Meine Variante: schwankt zwischen 28 und 29 ms

Also ist meine schneller als deine.

Hast du auch den Debugger ausgeschaltet? Falls nicht, ist klar, dass deine Variante schneller ist, weil so Sachen wie CountString() und ReadString() nicht debugt werden müssen. Aber bei meinem "Rumgepointere" wird jede einzelne Zeile übeeprüft, was alles ewig langsam macht.

Hier ein Vergleich mit Debugger:

Deine Variante 1: 41 ms, 57 ms, 45 ms
Meine Variante: 781 ms, 783 ms, 786 ms
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Textdatei in Array laden

Beitrag von ts-soft »

Und meine ist noch schneller :bounce:

Aber es geht noch schneller, man muß nur auf die Peeks in der Schleife verzichten.
Ausserdem vielleicht mit Fixstrings und CopyMemory arbeiten, usw.
Auf jedenfall kann man da noch was rausholen, aber die Frage ist: Tut dat not :lol:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Textdatei in Array laden

Beitrag von NicTheQuick »

ts-soft hat geschrieben:Und meine ist noch schneller :bounce:
War das Ironie? :mrgreen:
Ich messe hier 179 ms mit deiner Methode.
ts-soft hat geschrieben:Aber es geht noch schneller, man muß nur auf die Peeks in der Schleife verzichten.
Klar, dafür darf man halt den allozierten Speicher nicht freigeben und statt eines Stringarrays einfach nur Pointer auf die Stellen zurückgeben, die man braucht. Wenn man aus den Zeilenumbruchzeichen im Speicher Nullbytes macht, dann funktioniert PeekS() da wieder einwandfrei, aber eben nur zum Lesen.

///Edit:
Hab meinen Code oben etwas verändert, damit keine extra Structure mehr nötig wird.
Benutzeravatar
rolaf
Beiträge: 3843
Registriert: 10.03.2005 14:01

Re: Textdatei in Array laden

Beitrag von rolaf »

NicTheQuick hat geschrieben:Ich weiß zwar nicht wie du testest, aber das Ergebnis hat mich gewundert und ich habe selbst mal getestet.

Ergebnis bei einer 1,3 MB Datei mit 31780 Zeilen unter meinem System nach mehreren Tests wegen Dateicachings:

Deine Variante 1: mehrmals genau 32 ms
Meine Variante: schwankt zwischen 28 und 29 ms

Also ist meine schneller als deine.
Dafür ist "meiner/ts-softers" kürzer als deiner. :lol:

Und klaro ist der Debuger eingeschaltet, was du schon an den Debug-Ausgaben sehen kannst. Also gut, hast den schnellsten und den längsten, soll im Startpost gebührend erwähnt werden. :wink:

Für mich ist der "Contest" damit beendet, muß mich heute auf neue Aufgaben einlassen - sonst erlebe ich die nicht mehr. :mrgreen:
:::: WIN 10 :: PB 5.73 :: (x64) ::::
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8812
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Textdatei in Array laden

Beitrag von NicTheQuick »

DrFalo hat geschrieben:Also gut, hast den schnellsten und den längsten, soll im Startpost gebührend erwähnt werden. :wink:
:lol:

Ich will trotzdem noch etwas hinzufügen.
Ich habe mittlerweile schon oft die Erfahrung gemacht, dass die längeren Codes auch die schnelleren sind. Bei meinem hängt das damit zusammen, dass ich für ASCII, UTF-8 und Unicode einzelne Scan-Routinen gebastelt habe. Genauer gesagt fehlt die Routine für UTF-8 ja noch, also der Code wird noch länger.

Ich habe das auch schon bei meiner Raytracing-Engine gemerkt, die wir letztes Semester in C++ schreiben mussten. Und zwar gibt es beim GCC die Kompileroptionen zum automatischen Optimieren. Stufe 1 erhöht die Geschwindigkeit, Stufe 2 macht die Executable kleiner und Stufe 3 macht beides gleichzeitig. Rate mal, was im Nachhinein am schnellsten war... Es war Stufe 1, da dort viele Funktionen und Methoden gar nicht erst aufgerufen wurden, sondern deren Inhalt direkt an die Stelle im Code gesetzt wurde, wo sie aufgerufen werden sollte. So musste nichts auf den Stack gepusht werden, was alles einiges schneller machte.

Zugegeben ist das jetzt nichts, was hier bei mir passiert ist. Bei mir liegt es wohl eher an dem Select, dass ich um die Zeitintensive Schleife gesetzt habe, obwohl in der Schleife fast alles gleich ist. Hätte ich das Select in die Schleife an die Stelle gesetzt, wo die Unterschiede sind, würden jedes Mal ein Vergleich für ASCII, zwei für UTF-8 und sogar drei für Unicode gemacht werden.

Naja, genug gelabert für heute morgen. Ich muss mich jetzt fertig machen für die Uni. :D
Antworten