fopen, erst lesen und danach schreiben
Joachim
- php
0 Juan-4 fastix®1 Sven Rautenberg0 Joachim
1 dedlfix
0 Joachim
Hi,
ich oeffne eine Datei mit fopen(..., "r+") um sie erst zu lesen und dann zu beschreiben. (mit w+ kann man wohl nur schreiben und danach lesen..?).
Mit fgets hole ich mir also die erste Zeile, werte sie aus, setze den Dateizeiger mit rewind zurueck und beschreibe die Zeile mit einem modifizierten String.
Das klappt auch, allerdings bleiben hinter dem neuen String Reste des vorherigen Strings stehen, sofern dieser laenger war. Hat jemand einen Tipp fuer mich, wie ich es elegant loesen kann, dass die ganze Zeile ueberschrieben wird?
Gruesse, Joachim
Moin,
Das klappt auch, allerdings bleiben hinter dem neuen String Reste des vorherigen Strings stehen, sofern dieser laenger war. Hat jemand einen Tipp fuer mich, wie ich es elegant loesen kann, dass die ganze Zeile ueberschrieben wird?
eine (eher schlechte) Möglichkeit wäre z.B. dir Länge der ursprünglichen Zeile zu merken und deinen neue Zeile mit Hilfe von str_pad auf diese Länge mit z.B. Leerzeichen zu füllen.
MfG,
Juan
Moin!
Hat jemand einen Tipp fuer mich, wie ich es elegant loesen kann, dass die ganze Zeile ueberschrieben wird?
edit_firstline.sh:
#! /bin/sh
lines=wc -l datei | cut -d\ -f1
;
lines=echo $lines-1 | bc
;
file=tail -n $lines datei
;
echo -e "$*\n$file" > datei
edit_firstline.php:
<?php
$strNewFirstLine='Neue Zeile';
./edit\_firstline.sh '$strNewFirstLine'
;
?>
tested...
Die Datei edit_firstline.sh benötigt das Recht zum Ausführen für jedermann
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Moin!
Eine andere Möglichkeit wäre die Datei mittels
$arZeilenDerDatei=file('datei'); # in einen Array einzulesen, mit
$strErsteZeile=$arZeilenDerDatei[0]; # die erste Zeile auszulesen und mit
$arZeilenDerDatei[0]="Neuer Text"; zu überschreiben, weiter:
$strNeuerDateiInhalt = implode("\n", $arZeilenDerDatei);
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Moin!
Seit wann ist etwas funktionierendes "nicht hilfreich"?
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Hi fastix®!
Seit wann ist etwas funktionierendes "nicht hilfreich"?
Seit dem dies das _SELF_HTML-Forum ist. Die Energie des Verstehens...
MfG H☼psel
Moin!
Seit dem dies das _SELF_HTML-Forum ist. Die Energie des Verstehens...
Aha. Nun ja. Ich versuche mit den Beispielen darauf hinzuweisen, dass die shell oft sehr gute Möglichkeiten bietet.
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Hi,
Seit wann ist etwas funktionierendes "nicht hilfreich"?
Seit dem dies das _SELF_HTML-Forum ist. Die Energie des Verstehens...
Nun ja, das ist imho jetzt Haarspalterei. Manchmal brauchts durchaus ein Arbeitsbeispiel, um es SELF nachvollziehen zu koennen. Ausserdem sollte der Grad der Hilfestellung durchaus demjenigen ueberlassen bleiben, der die Hilfe anbietet.
Gruesse, Joachim
Moin!
Seit wann ist etwas funktionierendes "nicht hilfreich"?
Vielleicht, weil deine Lösung zu speziell ist. Nur die erste Zeile zu ändern hilft ja nicht, wenn man dann auch mal die zweite Zeile ändern will.
Und dein Programm so zu verändern, dass es EINE beliebige Zeile ändert, hilft nicht, wenn man gleich ganze Zeilenblöcke ändern will.
Abgesehen davon kostet das Aufrufen einer Shell auch Ressourcen, die über den Speicherbedarf einer kleinen Datei hinausgehen können. Und große Dateien erfordern ohnehin andere Maßnahmen.
- Sven Rautenberg
hi,
unabhängig davon, von wem die negative Bewerung kam:
Es hätte dem ursprünglichen Fragesteller ziemlich sicher wesentlich mehr geholfen, wenn diese Gegenargumente zu fastix' Vorschlag auch gleich genannt worden wären - nur an Hand einer negativen Bewertung vermag der OP vermutlich eher nicht zu erkennen, wo die Nachteile dieses Vorschlages liegen.
Zumindest ist dies jetzt nachgeholt.
gruß,
wahsaga
Moin!
Vielleicht, weil deine Lösung zu speziell ist. Nur die erste Zeile zu ändern hilft ja nicht, wenn man dann auch mal die zweite Zeile ändern will.
Und dein Programm so zu verändern, dass es EINE beliebige Zeile ändert, hilft nicht, wenn man gleich ganze Zeilenblöcke ändern will.
Wenn der Topf aber nun ein Loch hat! Lieber Svehen- was dann?
Wenn ich eine Lösung für alle möglichen und unmöglichen Problem dieser Welt anbieten soll müsste ich schreiben: "Benutze ein für alle denkbaren oder undenkbaren Aufgabenstellungen geeigenete Hardware mit für alle denkbaren oder undenkbaren Aufgabenstellungen geeigneter Software". Dann könnte dieses Forum schließen, weil immer nur diese eine Antwort zu lesen wäre langweilig.
Abgesehen davon kostet das Aufrufen einer Shell auch Ressourcen, die über den Speicherbedarf einer kleinen Datei hinausgehen können. Und große Dateien erfordern ohnehin andere Maßnahmen.
Bis hin zu ein paar vielen Megabyte dürfte das Skript wunderbar laufen. Wenn es um Speicheroptimierungen geht kann man auch da noch was ändern, z.B. den "Rest" der Datei in eine andere schreiben und so weiter und so fort. Hier ein Programm in c oder cpp anzubieten wäre aber echt ein wenig happig oder?
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
Moin!
Ok. Ich kommentiere das.
edit_firstline.sh:
#! /bin/sh
Das ist die sogenannte Shebang Diese bestimmt den Interpreter für das Skript. Grund: Unix/Linux verwendet keine Dateiendungen (ok. konqueror/kfm, also in grafischen Oberflächen gibt es das... die haben wir aber nicht: also shebang.)
lines=
wc -l datei | cut -d\ -f1
;
Es werden die Zeilen der Datei 'datei' gezählt. wc -l macht das. das gibt aber sowas wie: 100 datei zurück. Deshalb wird das Erfebnis durch ein Pipe zu cut geschickt. Dieses kann Spalten aus allem, was nach Tabelle riecht zurückgeben. Die Option -d bestimmt das Trennzeichen. Dieses ist ein Leerzeichen. Um es vor der Shell verborgen zu übergeben steht vor dem Leerzeichen der Backslash. Dann folgt das maskierte Leerzeichen und eines, welches den Optionsparameter "leerzeichen" von der nächsten Option trennt. Die ist '-l', braucht keinen Parameter und sorgt dafür dass, wc nicht alles mögliche, sondern die Zeilen zählt.
Die Anzahl der Zeilen befindet sich danach in der Variable 'lines', die auch mit 'echo $lines' abgefragt werden kann.
lines=
echo $lines-1 | bc
;
Das geschieht hier. Dem mächtigen Rechenprogramm 'bc' wird z.B. 100-1 übergeben. Das rechnet aus und übergibt das Ergebnis an die Variable lines.
file=
tail -n $lines datei
;
tail -n 20 gibt die letzten 20 Zeilen einer Datei zurück. in $lines steht die Anzahl der Zeilen-1: es werden alle Zeilen außer der ersten zurückgegeben. Die stehen jetzt in der Variable 'file'.
echo -e "$*\n$file" > datei
echo kann über die Umleitung der Standardausgabe in Dateien schreiben.
echo "Hallo Welt!"> datei schreibt "Hallo Welt!" in die Datei datei.
Die Option -e bewirkt, dass statt \n ein Zeilenumbruch geschrieben wird. In $* stehen alle an das Skript übergebene Parameter, die werden also zuerst in die Datei geschrieben. Das ist die neue erste Zeile. Dann der Zeilenumbruch, hernach der Rest der Datei.
Übrigens: Leerzeichen sind wichtig, z.B. bei variable=wert darf kein Leerzeichen rechts oder links des '=' stehen!
edit_firstline.php:
<?php
$strNewFirstLine='Neue Zeile';
Das ist der Inhalt der künftigen ersten Zeile.
./edit\_firstline.sh '$strNewFirstLine'
;
Hier wird das Skript aufgerufen und bekommt als Parameter den Inhalt der künftigen ersten Zeile übergeben. Thats all....
?>
MFFG (Mit freundlich- friedfertigem Grinsen)
fastix®
P.S.
Endlich: Spamer wurde wegen Betrugs und Titelmissbrauchs verurteilt
Hi,
Ok. Ich kommentiere das.
Wow! Sehr maechtig. Aber in meinem Falle etwas zu viel des Guten. Ich wollte lediglich ein zwiefaches fopen vermeiden...
Danke und Gruesse, Joachim
Moin!
Das klappt auch, allerdings bleiben hinter dem neuen String Reste des vorherigen Strings stehen, sofern dieser laenger war. Hat jemand einen Tipp fuer mich, wie ich es elegant loesen kann, dass die ganze Zeile ueberschrieben wird?
Dateien funktionieren anders!
Angenommen, du hast eine Datei mit zwei Zeilen Text darin. Die erste Zeile enthält 10 Zeichen plus \n (insgesamt also 11), und die zweite Zeile enthält 5 Zeichen plus \n (insgesamt also 6). Die Datei ist damit 11 + 6 = 17 Byte groß.
Veranschaulichung:
0123456789\n24680\n
Szenario 1: Du schreibst in Zeile 1 einen kürzeren Zeilentext von 8 Zeichen hinein ("xxxxxxxx"). Das hat zur Folge, dass die Bytes an Position 9, 10 und 11 unverändert bleiben.
xxxxxxxx90\n24680\n
Szenario 2: Du fügst an das Ende der X noch eine Zeilenschaltung ein - dadurch erhälst du DREI Zeilen:
xxxxxxxx\n0\n24680\n
Szenario 3: Du schreibst 12 X in die Originaldatei - damit löschst du Teile der zweiten Zeile.
XXXXXXXXXXXX\n680\n
Wenn du wirklich überflüssigen Text der Datei löschen willst oder neuen Text in der Mitte einfügen, mußt du die gesamte Datei neu schreiben, und logischerweise die Datei vorher auch komplett einlesen. Lediglich wenn du eine Dateistruktur hast, die mit garantiert festen Zeilenlängen operiert (z.B. 80 Zeichen plus \n), kannst du selektiv an ganz bestimmten Stellen schreiben - mußt dir aber trotzdem ein "hier steht nichts"-Zeichen überlegen für Zeilen, die (zumindest optisch) kürzer sind, als 80 Zeichen. Und Zeilen, die länger sind, müssen zwangsweise an der 80. Position in die nächste Zeile fließen - was unter umständen heftige Verschiebeoperationen zur Folge haben kann.
- Sven Rautenberg
Hi,
mußt dir aber trotzdem ein "hier steht nichts"-Zeichen überlegen für Zeilen, die (zumindest optisch) kürzer sind, als 80 Zeichen.
Danke Dir fuer die Erklaerung.
Ich hatte auch eine Loesung gebaut, welche die Datei mit Leerzeichen auffuellt, aber eigentlich brauchts das gar nicht. Simpler ist es fuer mich, Lesen und schreiben dann einfach zu trennen.
Gruesse, Joachim
Moin!
Ich hatte auch eine Loesung gebaut, welche die Datei mit Leerzeichen auffuellt, aber eigentlich brauchts das gar nicht. Simpler ist es fuer mich, Lesen und schreiben dann einfach zu trennen.
Das Problem, was dann auftritt: Ein anderer Prozess kann dir in dein Dateilocking reinbrechen, denn zwischen fclose() und erneutem fopen() ist die Datei frei verfügbar und kann ungünstig geändert werden.
Soll heißen: Wenn dein Dateilesen ergibt, dass du Schreiben darfst, dann die Pause erfolgt, in der ein anderer Prozess schreibt oder liest, und dann du schreibst, hat sich die Situation geändert, und du überschreibst vielleicht etwas.
- Sven Rautenberg
Hi,
Das Problem, was dann auftritt: Ein anderer Prozess kann dir in dein Dateilocking reinbrechen, denn zwischen fclose() und erneutem fopen() ist die Datei frei verfügbar und kann ungünstig geändert werden.
Danke fuer den Hinweis. Ich arbeite aber mit einer extra Lock-Datei, die nicht diejenige ist, die modifiziert wird. Ich denke so kann ich das umgehen.
Gruesse, Joachim
echo $begrüßung;
Hat jemand einen Tipp fuer mich, wie ich es elegant loesen kann, dass die ganze Zeile ueberschrieben wird?
Dateien kennen das Konzept "Zeile" nicht. In Dateien steht eine Bytefolge, die vielleicht zwischendrin ein Byte oder eine Bytefolge enthält, die andere Prozesse als Zeilenende erkennen. Wenn ein Teil einer Datei länger oder kürzer werden soll, musst du dafür sorgen, dass der Rest hintendran entsprechend verschoben wird.
Es ist unter anderem üblich, die Datei komplett in einen Puffer einzulesen (z.B. ein Array) und nach Bearbeitung dieses Puffers, die Datei mit dessen Inhalt komplett neu zu schreiben.
Man kann auch mit Hilfe einer zweiten Datei, den ersten Teil dorthin auslagern, dann den bearbeiteten Teil, und dann den Rest. Und mit etwas Dateinamensakrobatik bekommt man den alten Namen wieder hin.
Beachte auch, dass unter einer Multiuser-Umgebung sichergestellt werden muss, dass zwei Prozesse nicht gleichzeitig die selbe Datei bearbeiten.
echo "$verabschiedung $name";
Hi,
Es ist unter anderem üblich, die Datei komplett in einen Puffer einzulesen (z.B. ein Array) und nach Bearbeitung dieses Puffers, die Datei mit dessen Inhalt komplett neu zu schreiben.
Ideal waere fuer mich gewesen, die Datei mit einem fopen lesen und komplett neu beschreiben zu koennen, nun muss ich halt zwei Schritte daraus machen.
Beachte auch, dass unter einer Multiuser-Umgebung sichergestellt werden muss, dass zwei Prozesse nicht gleichzeitig die selbe Datei bearbeiten.
hehe, genau um andere Dateien zu sperren dient das Ganze ;-)
Sie selbst wird waehrend des Lese-Schreibevorgangs mit flock gesperrt.
Gruesse, Joachim