Bestimmte Zeilen in einer Textdatei löschen - performanter gestalten?

Hallo Leute,

ich schreibe jede Minute, die Maximalwerte die ich alle 5 Sekunden aus meiner Wetterstation lese und zwischenspeichere in eine Textdatei.
Zu jeder vollen Stunde starte ich WSWin32, welches per Dateiüberwachung wiederum die Daten einliest, weiter verarbeitet und aufbereitet per FTP auf die Website lädt.

Die Daten sind im folgenden Format gespeichert und werden fortlaufend geschrieben:

14.03.2021;00:09;3.1;18.7;-18;92.9;944.1;0;13.3;285.7;0;0
14.03.2021;00:10;3.1;18.7;-18;93;944.1;0;12.6;174.3;0;0
14.03.2021;00:11;3.1;18.7;-18;93;944.1;0;10.4;186.1;0;0
14.03.2021;00:12;3.1;18.7;-18;93;944.1;0;7.2;193.3;0;0
14.03.2021;00:13;3.1;18.7;-18;92.9;944.3;0;7.9;226.6;0;0
14.03.2021;00:14;3.1;18.7;-18;92.9;944.2;0;11.9;265.3;0;0
14.03.2021;00:15;3.1;18.7;-18;92.9;944.1;0;11.2;183.5;0;0
14.03.2021;00:16;3.1;18.7;-18;92.9;944;0;14;228;0;0


15.03.2021;16:07;5.7;18.7;-18;68.9;951.6;0;8.3;209.1;48007;188.46
15.03.2021;16:08;5.8;18.7;-18;68.9;951.7;0;8.6;304.6;12647;128.29
15.03.2021;16:09;5.9;18.7;-18;68.4;951.6;0;21.6;260.2;10643;145.4
15.03.2021;16:10;5.8;18.7;-18;68.3;951.7;0;12.2;291.7;10416;106.47
15.03.2021;16:11;5.7;18.7;-18;68.3;951.6;0;9;235.4;10962;91.13

So wächst und wächst die Datei und wenn ich es nicht vergessen habe, bereinigte ich gelegentlich die Daten manuell.
Nun habe ich mir ein kleines Script geschrieben, welches ich einmal täglich starte und die Daten von vorgestern löschen lasse um das zu automatisieren.

<?
// CSV-Datei für WsWin-Dateiüberwachung kürzen (Daten von vorgestern löschen)		
			
		$vorgestern = date("d.m.Y", strtotime("-2 days"));
		$file = file("H:/IP-Symcon/daten/wetter/wswin_import.csv");
		$a = 0;
		$id = $vorgestern;
		foreach($file as $zeile)
			{
			$zeile_explode=explode(";",$zeile);
			if($zeile_explode[0]==$id)
				{
				unset($file[$a]);
				$inhalt_neu=fopen("H:/IP-Symcon/daten/wetter/wswin_import.csv","w");
				fputs($inhalt_neu,implode("",$file));
				fclose($inhalt_neu);
				}
			$a++;
			}
?>

Das funktioniert soweit ganz gut, nur würde ich gerne die Bereinigung nur 1mal monatlich starten und dann die Daten am ersten eines Monats vom vorletzten Monat löschen.
Hintergrund, wenn man das nicht täglich beaufsichtigt, die Software mal hängen bleibt, gehen die Daten verloren.
Zwar sichere ich die Daten noch eine zu jedem Monat neu angelegte Datei, aber dann müsst wieder viel Hand angelegt werden um die Daten zu rekonstruieren.
Dazu müsste nur die explode-Zeile angepasst werden, aber ich habe ein Problem. Das Script läuft in einen Timeout.
Jede Minute eine Zeile macht am Tag 1440 Zeilen und im Monat mit 31 Tagen, 44640 Zeilen.

Zum löschen der vorgestrigen Daten braucht das Script auf meinem kleinen noch verwendeten Atom-N270 MiniPC mit 2GB RAM** allein ca. 6-7 Sekunden.
Da kann man sich ausrechnen, wie lang das Script für die Daten eines ganzen Monats braucht.

**Neue Hardware(i7-10510U, 16GB RAM) ist schon angeschafft, nur IPS und alles drum und dran (ist ne Menge) noch nicht umgezogen und auch dann wäre meine Frage:

Hat jemand eine Idee, wie man das Vorgehen resp. Script performanter gestalten kann?

Vielen Dank vorab für eure konstruktiven Ideen!

Gruß
nancilla

Nur so eine Idee. Was wäre wenn du deine Datei durchliest und nur jene Datensätze in eine andere Datei schreibst, die du willst und den Rest ins Nirvana schickst. Wenn das fertig ist, die Originaldatei löschen und die neue umbenennen.
So wie ich das lese machst du bei jeder Zeile die Datei auf und dann wieder zu. Ich schätze hier bleibt die meiste Zeit liegen.

Wenn es Unix wäre würde ich sagen

grep "^<datum>;" wswin_import.csv >>wswin_import_<datum>.csv

weiss leider nicht, wie das Pendant in Windows heisst, wingrep?

Evtl tut es auch ein analoges preg_match in php

Super!

„findstr“ ist der Windowspendant und geht sau schnell. Das ist es wohl :+1:
Außerhalb von php habe ich garnicht geschaut. :face_with_hand_over_mouth: Mit preg_match habe ich auch schon erfolglos probiert.
Danke euch für die Ideen! Haben mir sehr weitergeholfen.

Mein (dokumentiertes) Ergebnis wollte ich nicht schuldig bleiben:

$inputfile = 'wswin_import.csv';				// Eingabedatei
$outputfile = 'wswin_import_output.csv';		// Ausgabedatei
$pfad = 'H:\\IP-Symcon\\daten\\wetter\\';		// Dateiordnerpfad
$cmd = '%SystemRoot%\\System32\\findstr.exe'; 	// Windowspfad zum Kommando
$parameter = '/b /v'; 							// /b = Sucht am Zeilenanfang. /v = Gibt Zeilen aus, die die Zeichenfolge nicht enthalten.
$tag = date('d');


// am ersten Tag des Monats die Daten des vorletzten Monats, sonst Daten vom selben Tages des Vormonats löschen		
// *** (.. = Platzhalter, sonst 01-31)	/	-x month = vor x Monat(en) ***				
	if ($tag == 01) 
		{
		$tag = '..';
		$monat = date("m.Y", strtotime("-2 month"));
		}else{
		$tag = $tag;
		$monat = date("m.Y", strtotime("-1 month"));
		}	

$suchstring = $tag.'.'.$monat;					// Datum(Monat) nachdem gesucht wird
		//echo $suchstring;	

// alte Ausgabedatei löschen, wenn sie existiert
	if (file_exists($pfad.$outputfile)) 
		{unlink($pfad.$outputfile);}

// Eingabedatei nach Datum durchsuchen und nicht übereinstimmende Zeilen in Ausgabedatei schreiben
	// *** Wartet auf das Ende der Ausführung ***
	$commandString = $cmd.' '.$parameter.' '.$suchstring.' '.$pfad.$inputfile.' >> '.$pfad.$outputfile;
	pclose(popen($commandString, 'r'));

// Eingabedatei löschen
	unlink($pfad.$inputfile);
	
// Ausgabedatei zu Eingabedatei umbenennen
	rename($pfad.$outputfile, $pfad.$inputfile);

Scriptlaufzeit bei 2 Monatsdaten, also knapp 90000 Zeilen, ca. 7 sec auf meinem betagten PC, sonst im unteren 3stelligen ms-Bereich. :sunglasses: