PHP/Dateien lesen und schreiben: Unterschied zwischen den Versionen
Michi (Diskussion | Beiträge) |
Michi (Diskussion | Beiträge) Keine Bearbeitungszusammenfassung |
||
Zeile 11: | Zeile 11: | ||
|- | |- | ||
| <tt>fgets</tt> || Liest von der Position des Dateizeigers aus einer Datei, bis eines der folgenden Ereignisse eintritt. | | <tt>fgets</tt> || Liest von der Position des Dateizeigers aus einer Datei, bis eines der folgenden Ereignisse eintritt. | ||
* Die angegebene Anzahl | * Die angegebene Anzahl Byte ("<laenge>") ist erreicht. | ||
* Ein Zeilenende (Zeilenumbruch "\n") wurde erreicht. | * Ein Zeilenende (Zeilenumbruch "\n") wurde erreicht. | ||
* Das Dateiende wurde erreicht. | * Das Dateiende wurde erreicht. | ||
Zeile 23: | Zeile 23: | ||
|- | |- | ||
| <tt>fread</tt> || Liest Binärdaten aus einer Datei. Die Funktion entspricht fast der Funktion "fgets", interpretiert aber nicht den Zeilenumbruch. Damit wird tatsächlich bis zum Dateiende oder die angegebene Anzahl | | <tt>fread</tt> || Liest Binärdaten aus einer Datei. Die Funktion entspricht fast der Funktion "fgets", interpretiert aber nicht den Zeilenumbruch. Damit wird tatsächlich bis zum Dateiende oder die angegebene Anzahl Byte gelesen; die Funktion kann daher auch für Binärdateien genutzt werden. Das folgende Beispiel liest vier KB aus einer Datei, die vom Handle "$handle" adressiert wird. | ||
{| class=wikitable width=100% | {| class=wikitable width=100% | ||
| | | | ||
<source lang=php enclose=div> | <source lang=php enclose=div> | ||
$ | $bytestream = fread($handle, 4096); | ||
</source> | </source> | ||
|} | |} | ||
Zeile 61: | Zeile 61: | ||
|- | |- | ||
| <tt>fputs<br>fwrite</tt> || Schreibt Daten an die Stelle des Dateizeigers in eine Datei. "fwrite" ist lediglich ein Alias für "fputs". Die Angabe der Länge "<laenge>" ist optional; wird sie angegeben, so wird nur diese Anzahl | | <tt>fputs<br>fwrite</tt> || Schreibt Daten an die Stelle des Dateizeigers in eine Datei. "fwrite" ist lediglich ein Alias für "fputs". Die Angabe der Länge "<laenge>" ist optional; wird sie angegeben, so wird nur diese Anzahl Byte geschrieben. | ||
{| class=wikitable width=100% | {| class=wikitable width=100% | ||
Zeile 375: | Zeile 375: | ||
|- | |- | ||
| <tt>filesize</tt> || Gibt die Dateigrösse in | | <tt>filesize</tt> || Gibt die Dateigrösse in Byte zurück. | ||
|- | |- | ||
| <tt>filetype</tt> || Gibt den Dateityp als Zeichenkette zurück. Zulässige Werte sind: "block", "char", "dir", "fifo", "file" und "link". | | <tt>filetype</tt> || Gibt den Dateityp als Zeichenkette zurück. Zulässige Werte sind: "block", "char", "dir", "fifo", "file" und "link". |
Version vom 26. Februar 2010, 22:32 Uhr
Dateifunktionen
Dateien zu lesen und zu schreiben gehört zu den elementaren Vorgängen. Dazu werden folgende Funktionen verwendet.
Funktion | Beschreibung | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
readfile | Liest eine Datei und sendet sie an den Webbrowser. | |||||||||||||||
file | Liest die gesamte Datei in ein Array ein. Als Trennzeichen werden die Zeilenumbrüche verwendet, die dabei erhalten bleiben. | |||||||||||||||
fgets | Liest von der Position des Dateizeigers aus einer Datei, bis eines der folgenden Ereignisse eintritt.
| |||||||||||||||
fread | Liest Binärdaten aus einer Datei. Die Funktion entspricht fast der Funktion "fgets", interpretiert aber nicht den Zeilenumbruch. Damit wird tatsächlich bis zum Dateiende oder die angegebene Anzahl Byte gelesen; die Funktion kann daher auch für Binärdateien genutzt werden. Das folgende Beispiel liest vier KB aus einer Datei, die vom Handle "$handle" adressiert wird.
| |||||||||||||||
fopen | Öffnet eine Datei oder einen URL unter Angabe eines Dateinamens und eines Attributs. Das zurückgegebene Handle wird von anderen Funktionen verwendet, um auf die Datei zuzugreifen.
Das Attribut bestimmt, auf welche Art die Datei geöffnet wird.
| |||||||||||||||
fputs fwrite |
Schreibt Daten an die Stelle des Dateizeigers in eine Datei. "fwrite" ist lediglich ein Alias für "fputs". Die Angabe der Länge "<laenge>" ist optional; wird sie angegeben, so wird nur diese Anzahl Byte geschrieben.
| |||||||||||||||
fclose | Schliesst das Handle zu einer geöffneten Datei. So werden die Systemressourcen geschont und anderen Prozessen der Zugriff ermöglicht.
|
Die Funktion "readfile" liest eine Datei und sendet den gesamten Inhalt ohne weitere Bearbeitung an die Standardausgabe - das ist normalerweise der Webbrowser. Am angegebenen Ort (hier "data/news.txt") muss sich natürlich tatsächlich eine Datei befinden, damit sie ausgelesen werden kann.
<b>Newsdatei lesen</b><br />
Und hier sehen Sie unsere aktuellen Neuigkeiten:
<hr noshade size="1">
<?php
$file = "data/news.txt";
echo "Ausgabe der Datei $file:<br />";
readfile($file);
?>
|
Newsdatei lesen Ausgabe der Datei data/news.txt: |
Die Funktion "file" liest eine Datei und legt den Inhalt in einem Array ab. Jede Zeile wird zu einem Element eines eindimensionalen Arrays. Der Zeilenumbruch bleibt am Ende des Elements. Das folgende Beispiel liest eine Datei ein und gibt sie zusammen mit Zeilennummern wieder aus.
<?php
$file = "data/news.txt";
echo "Ausgabe der Datei $file:<br />\n";
$filearray = file($file);
foreach($filearray as $num => $line)
{
printf ("%02d : %s<br />", $num, $line);
}
?>
|
Ausgabe der Datei data/news.txt: |
Das folgende Beispiel liest eine Datei zeilenweise und gibt nur die Zeile aus, die zu einem bestimmten Tag passt. Die auszulesende Textdatei hat dabei folgenden Inhalt.
[Mon] Heute beginnt die Woche! [Tue] Nur noch 4 Tage [Wed] Das Wochenende naht [Thu] Fast fertig [Fri] Freitag nach 1... [Sat] Was suchst Du hier heute? [Sun] Was suchst Du hier heute?
<b>Newsdatei lesen</b><br />
Und hier sehen Sie Neuigkeiten des Tages:
<hr noshade size="1">
<?php
$select = date("D", time());
$fp = fopen("data/news.txt", "r");
## Liest die nächste Zeile aus der angegebenen Datei. Der ganze
## Ausdruck wird "FALSE" wenn der Zugriff misslingt. Das ist
## normalerweise nur am Dateiende der Fall. Hier werden also
## Zugriff, Auslesen der Daten und Dateiendeprüfung in einem
## einzigen Ausdruck zusammengefasst.
while ($line = fgets($fp, 1000))
{
## Ein regulärer Ausdruck zur Prüfung, der den Wochentagsnamen und die
## eckigen Klammern am Zeilenanfang erkennt.
if (preg_match("/^\[[".$select."]+\]/", $line))
{
## Der Dateizeiger wird automatisch weitergesetzt, sodass die Ausgabe
## mit die nächste Zeile ausgibt.
echo fgets($fp, 1000)."<br />";
}
}
fclose($fp);
?>
|
Newsdatei lesen Was suchst Du hier heute?
|
Das folgende Beispiel schreibt das aktuelle Datum und die Uhrzeit sowie die IP-Adresse des Clients in eine Datei und gibt die Datei anschliessend aus. Wenn im Webbrowser wiederholt auf die Schaltfläche "Aktuelle Seite neu laden" bzw. "Aktualisieren" geklickt wird, kann man die Datei wachsen sehen. Das Beispiel funktioniert allerdings nur, wenn der Webbenutzer Schreibrechte im Unterverzeichnis "logdata" hat.
<b>Protokoll schreiben</b>
<?php
$logfile = "logdata/logfile.log";
$fp = fopen($logfile, "a");
$logline = sprintf("%s, %s\n", date("d.M.Y h:m:s"),
$_SERVER['REMOTE_ADDR']);
fputs($fp, $logline);
fclose($fp);
echo "<p>Das ist der Inhalt der Log-Datei:</p>\n";
echo "<pre>";
readfile($logfile);
echo "</pre>";
?>
|
Protokoll schreiben Das ist der Inhalt der Log-Datei: 14.Sep.2008 07:09:31, 127.0.0.1 |
Die Anzeige der Zeilenanzahl kann durch Verbindung der Funktionen "file" und "count" erreicht werden.
<b>Protokoll schreiben, Anwendung von file</b>
<?php
echo "<p>Die Log-Datei hat ";
echo count(file("logdata/logfile.log"));
echo " Zeilen.</p>\n";
?>
|
Protokoll schreiben, Anwendung von file Die Log-Datei hat 4 Zeilen. |
Manchmal wird der Inhalt einer Datei nicht in einem Array, sondern in einer einzigen langen Zeichenkette benötigt. Vor allem mit Hilfe regulärer Ausdrücke bieten sich gute Verarbeitungsmöglichkeiten an. Einen direkten Befehl gibt es nicht, jedoch eine einfache Befehlskombination. Zur Anwendung kommen die Funktionen "file" (holt die Datei in ein Array) und "implode" (verknüpft Arrayelemente zu einer Zeichenkette). Als Verknüpfungsparameter wird bei "implode" eine leere Zeichenkette ("") verwendet.
$superstring = implode("",(@file("datei.txt")));
|
Der Zugriff auf Dateien erfolgt immer sequentiell. Es können also niemals am Anfang oder mittendrin Zeilen eingefügt werden. "Anhängen" ist wörtlich zu nehmen - Daten können nur am Ende angefügt werden.
Ebenso probelmatisch ist das gezielte Löschen von Zeilen. Nur mit der Kombination mehrerer Befehle und entsprechendem Leistungsbedarf des Skript ist dies möglich. Das folgende Skript zeigt die grundsätzliche Vorgehensweise.
<?php
$datei = "data/muster.txt"; ## Name der Datei
echo "Originaldatei \"$datei\":<br />\n<pre>";
## Vollständiges Einlesen und Ausgeben der Datei
readfile($datei);
## Zu löschende Zeile
$line = 2;
## Datei wird in ein Array eingelesn
$myfile = file($datei);
## Löschen des betreffenden Elements "$myfile[$line]" aus dem Array
unset($myfile[$line]);
## Bearbeitetes Array wird wieder in die Datei geschrieben
$fh = fopen("{$datei}.bak", "w"); ## Schreibend öffnen
fputs($fh, implode("", $myfile)); ## Array in String
fclose($fh);
echo "</pre>\n<hr>\nBearbeitete Datei \"$datei.bak\":<br />\n<pre>\n";
readfile("{$datei}.bak");
echo "</pre>\n";
?>
|
Originaldatei "data/muster.txt": Zeile 1 Zeile 2 Zeile 3 Zeile 4 Bearbeitete Datei "data/muster.txt.bak": Zeile 1 Zeile 2 Zeile 4 |
Grosse Datenmengen sind auf diese Weise allerdings nur schwer handhabbar - in diesem Fall sollten besser Datenbanken verwendet werden, die auf diese Art der Manipulation spezialisiert sind. Wird nur lesend gearbeitet, so können auch die internen Dateizeiger genutzt werden. Beim Schreiben finden diese keine Berücksichtigung.
Dateizeiger-Funktionen
Für Operationen mit Dateizeigern werden folgende Funktionen verwendet.
Funktion | Beschreibung | |
---|---|---|
feof | Testet, ob der Dateizeiger am Dateiende (engl. end of file) steht. Die Funktion gibt "TRUE" zurück, wenn das Dateiende erreicht wurde.
| |
fgetc | Holt ein einzelnes Zeichen von der Position des Dateizeigers. | |
fgets | Liest eine bestimmte Zeichenanzahl oder bis zum Zeilenende einer Textdatei. Als Zeilenende wird jeder Zeilenumbruch "\n" erkannt.
| |
frewind | Setzt den Dateizeiger an den Dateianfang. | |
fseek | Setzt den Dateizeiger auf eine bestimmte Position in einer Datei. | |
ftell | Gibt die aktuelle Position des Dateizeigers zurück. |
Bei den zuvor gezeigten Beispielen wurde ausgenutzt, dass der Dateizeiger beim Lesen automatisch weiterwandert und beim Schreiben an das Ende der geschriebenen Zeichen gesetzt wird. Möchte man sich aber in einer Textdatei frei bewegen, so hilft nur eine gezielte Positionierung des Dateizeigers. Bei solchen Bewegungen ist es wichtig, nicht versehentlich über das Dateiende hinaus zu lesen. In diesem Fall bricht entweder die genutzte Funktion ab oder PHP reagiert mit einem Laufzeitfehler.
Die Funktion "ftell" gibt die aktuelle Position des Dateizeigers an. Damit kann eine bestimmte Position gemerkt, andere Operationen ausgeführt und dann mit "fseek" die alte Position wiedergefunden werden.
<?php
$file = "data/muster.txt";
$handle = fopen($file, "r");
rewind($handle);
fgets($handle, 20);
echo "Position des Zeigers: " . ftell($handle) . "<br />\n";
echo "Ausgabe: <tt>";
$pointer = ftell($handle);
for ($i = 0; $i <= 25; $i++) {
## Ausgabe in gesperrter Schrift
echo fgetc($handle) . " ";
}
echo "</tt><br />\n";
echo "Position des Zeigers: " . ftell($handle) . "<br />\n";
fseek($handle, $pointer);
echo "Position des Zeigers: " . ftell($handle) . "<br />\n";
?>
|
Position des Zeigers: 8 Z e i l e 4
|
Dateieigenschaften ermitteln
Funktion | Beschreibung | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
clearstatcache | Löscht den Status-Cache. Viele Funktionen ermitteln Daten über Dateien und legen diese in einem Speicher in PHP ab, damit spätere Zugriffe schneller ablaufen. Wird eine Datei mehrfach angefragt, so wird sich die Antwort nicht ändern, auch wenn sich die Dateieigenschaften geändert haben. Um die Daten zu aktualisieren muss dieser Status-Cache gelöscht werden. | ||||||||||||||||||||||||||||
filemtime | Gibt das Datum zurück, an dem die Datei letztmals geändert wurde. Der Rückgabewert ist der Unix-Zeitstempel, muss also (z. B. mit "date") für die Ausgabe formatiert werden. | ||||||||||||||||||||||||||||
fileowner | Ermittelt den Namen des Besitzers der Datei. | ||||||||||||||||||||||||||||
fileperms | Holt die Dateiattribute. Jedes Attribut belegt ein Bit im 2 Byte breiten Bitfeld. Es gelten folgende Werte:
| ||||||||||||||||||||||||||||
filesize | Gibt die Dateigrösse in Byte zurück. | ||||||||||||||||||||||||||||
filetype | Gibt den Dateityp als Zeichenkette zurück. Zulässige Werte sind: "block", "char", "dir", "fifo", "file" und "link". | ||||||||||||||||||||||||||||
is_dir | Ermittelt, ob der Name ein Verzeichnis ist. Im Erfolgsfall wird "TRUE" zurückgegeben. | ||||||||||||||||||||||||||||
is_executable | Ermittelt, ob die Datei ausführbar ist. Im Erfolgsfall wird "TRUE" zurückgegeben. | ||||||||||||||||||||||||||||
is_file | Ermittelt, ob es sich um eine reguläre Datei handelt. Im Erfolgsfall wird "TRUE" zurückgegeben. | ||||||||||||||||||||||||||||
is_link | Ermittelt, ob es sich um einen Link (Verweis) handelt. Im Erfolgsfall wird "TRUE" zurückgegeben. | ||||||||||||||||||||||||||||
is_readable | Ermittelt, ob die Datei lesbar ist. Im Erfolgsfall wird "TRUE" zurückgegeben. | ||||||||||||||||||||||||||||
is_writeable | Ermittelt, ob in die Datei geschrieben werden kann. Im Erfolgsfall wird "TRUE" zurückgegeben. | ||||||||||||||||||||||||||||
stat | Gibt in einem Array die folgenden Informationen über eine Datei zurück.
|
Um die Funktion "fileperms" anzuwenden, wird der Wert mit einem logischen "und" maskiert. Als Maskenwert wird eine Kombination aus den drei Einzelwerten angegeben. Sind alle Rechte erforderlich, entspricht das 7 (1 + 2 + 4). Zur Anzeige jedes Rechtes einzeln kann folgende Lösung interessant sein.
echo (fileperms($entry) & 4) ? "R" : "-";
echo (fileperms($entry) & 2) ? "W" : "-";
echo (fileperms($entry) & 1) ? "X" : "-";
|
Die Funktion "fileinfo" gibt die Grösse der Datei in Byte zurück. Mit der folgenden Funktion werden Umrechnungen in KByte oder MByte vorgenommen.
<?php
function GetRealVolume($v = 0)
{
if ($v > pow(2,10))
{
if ($v > pow(2,20))
{
$r = (integer)($v / pow(2,20));
$r .= " MB";
}
else
{
$r = (integer)($v / pow(2,10));
$r .= " KB";
}
}
else
{
$r = (string) $v . " Byte";
}
return $r;
}
$datei = "data/muster.txt";
echo GetRealVolume(filesize($datei));
?>
|
32 Byte |
Dateilisten filtern
Eine einfache Dateiliste lässt sich mit der Funktion "glob" erstellen. Das folgende Beispiel zeigt alle Skripte an, deren Dateinamen mit den Buchstaben "a" oder "b" beginnen.
<?php
$path = basename($_SERVER['PHP_SELF']);
$files = glob("{[ab]*.php}", GLOB_BRACE);
if (is_array($files))
{
foreach ($files as $filename)
{
echo "$filename<br>";
}
}
?>
|
array_asort.php array_keys.php array_merge.php array_multi.php ... |
Die Funktion "glob" kann mit den folgenden Schaltern gesteuert werden.
Schalter | Beschreibung |
---|---|
GLOB_BRACE | Die Platzhalter verwenden Aufzählungssymbolik: {*.txt, *.php} usw. |
GLOB_MARK | Fügt einen Schrägstrich an alle erkannten Einträge an. |
GLOB_NOCHECK | Gibt das Suchmuster zurück, wenn keine Dateien gefunden werden. |
GLOB_NOESCAPE | Metazeichen (Verzeichnistrennzeichen) werden nicht mit einem Backslash markiert. |
GLOB_NOSORT | Verhindert die Sortierung. (Standard ist eine alphabetische Sortierung) |
GLOB_ONLYDIR | Nur Verzeichnisse werden erkannt. |
Mehrere Schalter können über eine einfache oder-Verknüpfung ("|") kombiniert werden.
GLOB_BRACE | GLOB_ONLYDIR
Die Platzhalterzeichen erlauben folgende Angaben.
Schalter | Beschreibung | ||||||||
---|---|---|---|---|---|---|---|---|---|
{Platzhalter,Platzhalter} | Eine Serie von oder-verknüpften, durch Kommas getrennte Platzhalterzeichen innerhalb geschweifter Klammern. Das funktioniert, wenn der Schalter "GLOB_BRACE" verwendet wird. | ||||||||
* | Soll keinem oder einer beliebigen Anzahl Zeichen entsprechen. | ||||||||
? | Ersetzt genau ein beliebiges Zeichen. | ||||||||
[] | Genau ein Zeichen aus einer Zeichengruppe, die durch die Angabe in Klammer bestimmt wird. Das kann eine Aufzählung von Zeichen wie in den folgenden Beispielen sein.
|
Ersetzen in Dateien
Das mehrfache Ersetzen von Werten innerhalb einer Zeichenkette ist kein Problem, dafür stehen mehrere Funktionen zur Auswahl. Schwieriger wird es, wenn der Ersetzungsvorgang in einer Datei durchgeführt werden soll.
Folgende Funktion zum Ersetzen mit regulären Ausdrücken kann überall eingebaut werden, wo eine derartige Leistung erforderlich ist. Typisch ist die Anwendung zum dauerhaften "Verdichten" von HTML-Dateien durch Entfernung von Leerzeichen und Tabulatoren. Dazu muss der passende reguläre Ausdruck als erster Parameter übergeben werden. Die Dateien "replace.txt" und "replace.bak" müssen zu Beginn bereits vorhanden sein.
<?php
## Funktion wird mit drei Parametern aufgerufen
## - "$string1" ist die zu suchende Zeichenkette
## - "$string2" ist die Ersatzzeichenkette
## - "$filename" ist die Datei, in der gesucht werden soll
function massreplace($string1, $string2, $filename)
{
## Datei wird normal geöffnet
$fp = fopen($filename, "r");
## Dateigrösse wird ermittelt
$size = filesize($filename);
## Gesamte Datei wird in eine Variable eingelesen
$contents = fread($fp, $size);
## Datei wird geschlossen
fclose($fp);
## Ersetzungsvorgang wird durchgeführt (die Funktion "preg_replace"
## kann hier leicht durch eine eigene Konstruktion ersetzt werden)
$massreplace = preg_replace("/$string1/", $string2, $contents);
$fp = fopen($filename, "w");
## Veränderte Datei wird zurückgeschrieben
fputs($fp, $massreplace);
fclose($fp);
}
?>
<h3>Mehrfaches Ersetzen in einer Datei</h3>
<form method="post" action="<?=$_SERVER['PHP_SELF']?>">
<table>
<tr>
<td>Geben Sie ein Suchwort ein:</td>
<td><input type="text" name="search" value=""></td>
</tr>
<tr>
<td>Geben Sie den Ersatztest ein:</td>
<td><input type="text" name="replace" value=""></td>
</tr>
<tr>
<td align=right colspan="2"><input type="Submit" value="Ersetzen"></td>
</tr>
</table>
</form>
<table border="0" cellspacing="10">
<tr>
<th>Alte Version</th>
<th>Neue Version</th>
</tr>
<tr>
<td valign=top>
<?php
readfile("data/replace.txt");
echo "</td>";
$search = $_POST['search'];
$replace = $_POST['replace'];
if (isset($search) && isset($replace))
{
massreplace($search,
"<span style=color:red>$replace</span>",
"data/replace.txt");
}
echo "<td valign=top>";
readfile("data/replace.txt");
?>
</td>
</tr>
</table>
<?php
copy("data/replace.bak", "data/replace.txt");
?>
|
<html> Mehrfaches Ersetzen in einer Datei<form method="post" action="">
</form>
</html> |