|
bituniverse.com Entwickler Forum
|
| Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
| Autor |
Nachricht |
Jens Administrator
Anmeldedatum: 05.11.2007 Beiträge: 193
|
Verfasst am: Fr 09 Nov, 2007 21:25 Titel: Wie kommen meine Daten auf die Platte? |
|
|
Kapitel 1 - Vorüberlegungen
Heutzutage wird zwar zur Ablage von Daten in den meißten Fällen zu einer Datenbank gegriffen, ein paar grundlegende Informationen zum Thema Arbeiten mit Dateien können aber trotzdem nicht schaden.
Diese Tutorialserie beschreibt deshalb mehrere Verfahren zur Ablage von Daten in Dateien und versucht diese in einen Kontext zu ihrer Eignung für bestimmte beispielhafte Problemszenarien zu setzen.
Beginnen wir mit ein paar Vorüberlegungen:
Grundsätzlich geht es bei der Arbeit mit Daten immer um die folgenden Operationen.
- Speichern eines Datensatzes
- Lesen eines Datensatzes
- Verändern eines Datensatzes
- Löschen eines Datensatzes
- Finden eines Datensatzes
Zur Durchführung dieser Operationen muss zuerst grundlegend über den Lagerort entschieden werden. Das hier nicht ein Verfahren für alle möglichen Operationen die optimalste Leistung bringen kann, dürfte jedem einleuchten.
Eine Wahl über das geeignete Verfahren kann also nur dann getroffen werden, wenn die genauen Anforderungen bekannt sind.
Nun führen ja bekanntlich auch viele Wege nach Rom, und nicht jeder ist für jeden Zweck der optimalste. Stellen wir uns vor, ich wolle mit einem Container voll Waren nach Rom, dann währe mein gewählter Weg wohl am ehesten ein LKW und die Autobahn, während ich als Alleinreisender Geschäftsmann wohl eher in den Flieger steigen würde.
Gleiches gilt nun auch für die Arbeit mit Dateien. Je nach Art und Menge der geplanten Operationen, sowie nach der zu behandelnden Datenmenge unterscheidet ist das geeignete Verfahren für die Behandlung der Daten nicht unbedingt immer identisch.
Neben dem Wissen um die möglichen Verfahren, müssen also folgende Kriterien Berücksichtigung finden:
- Die Art der durchzuführenden Operationen
- Die Anzahl an zu tätigenden Operationen pro Zeiteinheit
- Die relative Häufigkeit der einzelnen Operationsarten
- Die bei den Operationen absolut zu bewegende Datenmenge
- Die Datenmengen pro Operation und Operationsart
Das hört sich aber natürlich wieder wilder an, als es ist. Konkret bedeutet dies nur, daß vor der Entscheidung für ein Verfahren die gewünschte Leistungsfähigkeit formuliert werden muss. Will ich zum Beispiel ein kleines Gästebuch entwickeln, wo pro Tag vielleicht zwei Beiträge geschrieben werden, und höchstens 20 Abrufe pro Tag stattfinden (sagen wir mal je 5 auf einmal), lässt sich ein Teil der obigen Kriterien leicht sammeln:
Zuerst einmal sagt die Rechtslage, daß ein Webmaster für alle Inhalte seiner Seite nach Kenntnisnahme mitverantwortlich ist, auch wenn er sie nicht selbst verfasst hat. Schon rein aus rechtlicher sich müssen wir also neben Schreiben und Lesen auch Editieren und Löschen unterstützen. Punkt 1) kann man also mit "alle 4" beantworten.
Die Anzahl der zu tätigenden Operationen liest sich schon aus den Vorbedingungen heraus:
- 100x Lesen pro Tag
- 2x Schreiben pro Tag
- <=2x Editieren pro Tag
- <=2x Löschen pro Tag
- <=104x Finden pro Tag
Ein Eintragschreiber schreibt ja nun normalerweise keine Buch. Der Text wird im Schnitt wohl unter 2kb pro Eintrag bleiben. Kalkulieren wir nun sagen wir mal mit einer (künstlich hoch gewählten) Lebensdauer von 5 Jahren, dann ergibt sich eine maximale Datenmenge von 3.5mb.
Aber halt. Zu einem Gästebucheintrag gehört ja mehr als nur der Text. Zu jedem Eintrag gehört auch noch ein Name des Authors (z.B. max 15 Byte), sowie Datum und Uhrzeit (wieder 15 Byte). Insgesamt landen wir also bei 3.6mb. Damit wäre der Punkt 4) auch vom Tisch.
Nun fehlt noch Punkt 5), aber auch das ergibt sich direkt aus den schon ermittelten Werten
- Lesen muss man pro Operation maximal 10kb
- Schreiben muss man pro Operation maximal 2kb
- Editieren muss man pro Operation maximal 2kb
- Löschen muss man ebenfalls maximal 2kb auf einmal
- Und durchsuchen muss man maximal 3.6mb
Auf Basis dieser Informationen könnte nun ein geeignete Verfahren gewählt werden. In den folgenden Kapiteln werde ich nun einige Verfahren an Beispielen beschreiben, wie Daten auf die Festplatte gebracht werden können. Anschließend werde ich noch für einige Beispielhafte Problemszenarien mehrere die Eignung der jeweiligen Verfahren gegenüberstellen.
Gruß Jens
|
|
| Nach oben |
|
 |
Jens Administrator
Anmeldedatum: 05.11.2007 Beiträge: 193
|
Verfasst am: So 11 Nov, 2007 01:05 Titel: |
|
|
Kapitel 2 - eine Zeile pro Datensatz
Ein gängiges Modell zur Organisation von Daten in einer Datei ist die Ablage eines zusammenhängenden Datensatzes in einer Zeile. Die Einzelelemente des Datensatzes werden dabei für gewöhnlich von einem möglichst seltenen Trennzeichen voneinander abgetrennt.
Nehmen wir an, unser Datensatz bestünde aus den folgenden Einzelteilen:
- Datum - Unix-Timestamp
- Inhalt - ein einfacher Text
Als Trennzeichen verwenden wir zwei aufeinander folgende Prozentzeichen.
| Code: |
1194730024%%Dies ist der erste Inhalt
1194729021%%Dies ist der zweite Inhalt
1194723027%%Dies ist der dritte Inhalt
|
Nun müssen wir noch den Code für die Eingangs genannten Operationen erstellen.
- Speichern eines Datensatzes
- Lesen eines Datensatzes
- Verändern eines Datensatzes
- Löschen eines Datensatzes
- Finden eines Datensatzes
Eine mögliche Realisierung wäre diese:
| Php: |
<?php
/**
* Diese Funktion hängt einen neuen Datensatz an die Datei an.
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $datum Ein Unixtimestamp
* @param String $inhalt Der Inhalt dieses Datensatzes
*/
function schreibe($dateiname, $datum, $inhalt)
{
// Prüfe Datei auf Existenz
{
return trigger_error(E_USER_ERROR, 'Die Datendatei existiert nicht und kann auch nicht angelegt werden.');
}else
{
// prüfe Dateiname auf Beschreibbarkeit
return trigger_error(E_USER_ERROR, 'Die Datendatei existiert, kann aber nicht beschrieben werden.');
}
// Öffne Datei. Wenn die Datei noch nicht existiert, wird diese angelegt
$fd= fopen($dateiname, 'a+');
// Überprüfe ob das Öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
// Zeilenumbrüche in $inhalt maskieren:
// neue Zeile für die Datei zusammenstellen:
$neueZeile="{$datum}%%{$inhalt}\r\n";
// neue Zeile ans Dateiende hängen
}
/**
* Diese Funktion liefert einen Datensatz zurück oder False falls dieser nicht existiert.
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
* @return array/false
*/
function lese($dateiname,$ordnungsnummer)
{
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
for($i= 0, $zeile= '';! feof($fd); $zeile= fgets($fd), $i++ )
{
// Zeilenumbruch abschneiden
// $datum und $inhalt extrahieren
// Zeilenumbrüche in $inhalt wieder herstellen
if($i==$ordnungsnummer)
{
return array('datum'=> $datum,
'inhalt'=>$inhalt);
}
}
return false;
}
/**
* Diese Funktion ersetzt einen durch die Ordnungsnummer identifizierten Datensatz
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
* @param integer $datum Ein neuer Unixtimestamp
* @param String $inhalt Der neue Inhalt dieses Datensatzes
*/
function ersetze($dateiname,$ordnungsnummer,$datum,$inhalt)
{
// temporäre Datei erstellen:
$tmpFile= tempnam(sys_get_temp_dir (), 'datafile_');
// temporäre Datei öffnen:
$tmpFd= fopen($tmpFile, 'a+');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die temporäre Datendatei konnte nicht geöffnet werden.');
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
for($i= 0, $zeile= '';! feof($fd); $zeile= fgets($fd), $i++ )
{
// Zeilenumbruch abschneiden
// $datum und $inhalt extrahieren
// Zeilenumbrüche in $inhalt wieder herstellen
if($i==$ordnungsnummer)
{
// übernehme neuen Datensatz
$inhaltNeu=$inhalt;
$datumNeu=$datum;
}else
{
// übernehme alten Datensatz
$inhaltNeu=$inhaltAlt;
$datumNeu=$datumAlt;
}
// Zeilenumbrüche in $inhalt maskieren:
$inhaltNeu= addcslashes($inhaltNeu, "\0..\37!@\@\177..\377");
// neue Zeile für die Datei zusammenstellen:
$neueZeile="{$datumNeu}%%{$inhaltNeu}\r\n";
// Neue Werte in temporäre Datei schreiben:
fputs($tmpFd, $neueZeile);
}
// und jetzt muss die Originaldatei noch durch die Temporäre ersetzt werden
}
/**
* Diese Funktion löscht einen durch die Ordnungsnummer identifizierten Datensatz
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
*/
function loesche($dateiname,$ordnungsnummer)
{
// temporäre Datei erstellen:
$tmpFile= tempnam(sys_get_temp_dir (), 'datafile_');
// temporäre Datei öffnen:
$tmpFd= fopen($tmpFile, 'a+');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die temporäre Datendatei konnte nicht geöffnet werden.');
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
for($i= 0, $zeile= '';! feof($fd); $zeile= fgets($fd), $i++ )
{
// Zeilenumbruch abschneiden
// $datum und $inhalt extrahieren
// handelt es sich um eine Zeile, die erhalten bleiben soll?
if($i!=$ordnungsnummer)
{
// neue Zeile für die Datei zusammenstellen:
$neueZeile="{$datumAlt}%%{$inhaltAlt}\r\n";
// Werte in temporäre Datei schreiben:
fputs($tmpFd, $neueZeile);
}
}
// und jetzt muss die Originaldatei noch durch die Temporäre ersetzt werden
}
/**
* Diese Funktion sucht einen Datensatz in einer Datei und liefert seine Nr zurück oder false.
* @param String $dateiname Der Name der Datei mit den Daten
* @param String $wo Wo soll gesucht werden ('datum' oder 'inhalt')
* @param Mixed $was was soll gesucht werden
* @return Integer/false
*/
function suche($dateiname,$wo,$was)
{
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
for($i= 0, $zeile= '';! feof($fd); $zeile= fgets($fd), $i++ )
{
// Zeilenumbruch abschneiden
// $datum und $inhalt extrahieren
// Zeilenumbrüche in $inhalt wieder herstellen
// Wenn gesuchtes Element, dann
if(${$wo}==$was)
{
// Dateihandle killen
// Ordnungsnummer zurück liefern
return $i;
}
}
return false;
}
?>
|
Vorteil dieser Variante ist die extrem leichte Implementierbarkeit. Wie leicht ersichtlich ist, basieren alle Operationen ausschließlich auf der Lese und der Schreib-Operation. Weiterer Vorteil ist die sehr einfache (und performante) Schreiboperation für neue Datensätze.
Nachteil ist hier allerdings, daß für das Verändern oder Löschen eines Datensatzes schlimmsten falls die komplette Datei neu geschrieben werden muss. Ein ähnlicher Aufwand für die Suche nach einem konkreten Datensatz an. Auch hier muss potentiell die komplette Datei durchsucht werden.
Ein weiterer Nachteil ist, daß das gewählte Trennzeichen nicht in einem der Datenfelder stehen darf. Ein Inhalt von %% würde uns den Datensatz zerschießen. Außerdem kann diese Variante keine Binärdaten verdauen.
Zuletzt bearbeitet von Jens am Do 03 Jan, 2008 12:25, insgesamt 2-mal bearbeitet |
|
| Nach oben |
|
 |
Jens Administrator
Anmeldedatum: 05.11.2007 Beiträge: 193
|
Verfasst am: So 11 Nov, 2007 18:48 Titel: |
|
|
Kapitel 3 - CSV
Nun sind wir ja nicht die ersten, die Daten in einer Datei ablegen wollen. Einer der Quasi-Standards ist die Ablage von Inhalten im sogenannten CSV-Format. Das Akronym CSV steht für Comma Separated Value, also für Kommata-getrennte-Werte. In der Basisform ist das nichts anderes, als das Modell aus Kapitel 2 mit einem Komma als Trennzeichen. Da Kommata allerdings die dumme Angewohnheit haben, in Texten recht häufig vor zu kommen, wurde das Konzept um Anführungszeichen um Strings erweitert. Kurz gesagt, werden alle nicht numerischen Werte in Anführungszeichen eingefasst, und im Text vorkommende Anführungszeichen werden entsprechend mittels eines Backslash ausmaskiert.
Zusätzlicher Vorteil dieser Methode ist, daß PHP mit den Funktion fgetcsv() und fputcsv() schon entsprechende Funktionen zum Handling je eines Datensatzes mit bringt. Grundsätzlich gilt, daß native PHP-Funktionen in den meißten Fällen schneller sind, als in PHP implementierter Code. Insofern schlägt diese Variante das im zweiten Kapitel vorgestellte Modell in der Performance um ein paar Prozent.
Definieren wir wieder den Code für die eingangs definierten Operationen:
- Speichern eines Datensatzes
- Lesen eines Datensatzes
- Verändern eines Datensatzes
- Löschen eines Datensatzes
- Finden eines Datensatzes
| Php: |
<?php
/**
* Diese Funktion hängt einen neuen Datensatz an die Datei an.
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $datum Ein Unixtimestamp
* @param String $inhalt Der Inhalt dieses Datensatzes
*/
function schreibe($dateiname, $datum, $inhalt)
{
// Prüfe Datei auf Existenz
{
return trigger_error(E_USER_ERROR, 'Die Datendatei existiert nicht und kann auch nicht angelegt werden.');
}else
{
// prüfe Dateiname auf Beschreibbarkeit
return trigger_error(E_USER_ERROR, 'Die Datendatei existiert, kann aber nicht beschrieben werden.');
}
// Öffne Datei. Wenn die Datei noch nicht existiert, wird diese angelegt
$fd= fopen($dateiname, 'a+');
// Überprüfe ob das Öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
// neuen Datensatz an Datei anhängen:
fputcsv ($fd, array($datum, $inhalt));
// Datei schließen
}
/**
* Diese Funktion liefert einen Datensatz zurück oder False falls dieser nicht existiert.
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
* @return array/false
*/
function lese($dateiname,$ordnungsnummer)
{
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
{
// handelt es sich um den gesuchten Datensatz?
if($i==$ordnungsnummer)
{
// schließe Dateihandle
// gebe Datensatz zurück
return array('datum'=> $ds[0],
'inhalt'=>$ds[1]);
}
}
// schließe Dateihandle
// gebe False zurück, da kein passender Datensatz gefunden
return false;
}
/**
* Diese Funktion ersetzt einen durch die Ordnungsnummer identifizierten Datensatz
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
* @param integer $datum Ein neuer Unixtimestamp
* @param String $inhalt Der neue Inhalt dieses Datensatzes
*/
function ersetze($dateiname,$ordnungsnummer,$datum,$inhalt)
{
// temporäre Datei erstellen:
$tmpFile= tempnam(sys_get_temp_dir (), 'datafile_');
// temporäre Datei öffnen:
$tmpFd= fopen($tmpFile, 'a+');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die temporäre Datendatei konnte nicht geöffnet werden.');
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
{
// muss der Datensatz ersetzt werden?
if($i==$ordnungsnummer)
{
// übernehme neuen Datensatz
$ds= array($datum, $inhalt);
}
// Neue Werte in temporäre Datei schreiben:
fputcsv($tmpFd,$ds);
}
// Dateien wieder schließen
// und jetzt muss die Originaldatei noch durch die Temporäre ersetzt werden
}
/**
* Diese Funktion löscht einen durch die Ordnungsnummer identifizierten Datensatz
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
*/
function loesche($dateiname,$ordnungsnummer)
{
// temporäre Datei erstellen:
$tmpFile= tempnam(sys_get_temp_dir (), 'datafile_');
// temporäre Datei öffnen:
$tmpFd= fopen($tmpFile, 'a+');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die temporäre Datendatei konnte nicht geöffnet werden.');
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
{
// handelt es sich um eine Zeile, die erhalten bleiben soll?
if($i!=$ordnungsnummer)
{
// Neue Werte in temporäre Datei schreiben:
fputcsv($tmpFd,$ds);
}
}
// Dateihandles schließen
// und jetzt muss die Originaldatei noch durch die Temporäre ersetzt werden
}
/**
* Diese Funktion sucht einen Datensatz in einer Datei und liefert seine Nr zurück oder false.
* @param String $dateiname Der Name der Datei mit den Daten
* @param String $wo Wo soll gesucht werden ('datum' oder 'inhalt')
* @param Mixed $was was soll gesucht werden
* @return Integer/false
*/
function suche($dateiname,$wo,$was)
{
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// Datei öffnen.
$fd= fopen($dateiname, 'r');
// Überprüfe ob das öffnen geklappt hat
return trigger_error(E_USER_ERROR, 'Die Datendatei konnte nicht geöffnet werden.');
// $wo in Ordnungsnummer übersetzen:
$translation= array('datum'=> 0, 'inhalt'=> 1);
if(! isset($translation[$wo]))
return trigger_error(E_USER_ERROR, 'Der Suchschlüssel existiert nicht.');
{
// Wenn gesuchtes Element, dann
if($ds[$translation[$wo]]==$was)
{
// Dateihandle killen
// Ordnungsnummer zurück liefern
return $i;
}
}
return false;
}
?>
|
Wie man sieht, ist diese Variante schon ein Stück weniger komplex. Außerdem behebt sie einige Probleme des Eigenbaus aus Kapitel zwei. Hier hätten wir keine Probleme, das Trennzeichen in den Inhalt eines Datensatzes zu schreiben.
Im prinzipiellen Aufbau ähneln sich beide Methoden aber noch ungemein. Auch hier haben wir also extrem performante Schreiboperationen, unser Aufwand für Ändern und Löschen ist aber nach wie vor recht hoch. Hinzu kommt natürlich auch hier die Gefahr von Race-Conditions und Deadlocks.
Diese Methode eignet sich allerdings sehr gut, wenn nicht nur PHP auf den Datenspeicher zugreifen soll, da es sich bei CSV um ein standardisiertes Format handelt.
Gruß Jens
Zuletzt bearbeitet von Jens am Do 03 Jan, 2008 12:24, insgesamt 2-mal bearbeitet |
|
| Nach oben |
|
 |
Jens Administrator
Anmeldedatum: 05.11.2007 Beiträge: 193
|
Verfasst am: Do 03 Jan, 2008 12:21 Titel: |
|
|
Kapitel 4 - serialisierte Listen
PHP bietet die Möglichkeit, beliebige Variableninhalte als String darzustellen oder aus einer solchen Darstellung zu laden. Der zugehörige Transformationsalgorithmus wird als Serialisieren bezeichnet. Zur Ablage von Daten könnten wir jetzt also beigehen und einfach jeden Datensatz mittels serialize() serialisieren. Beim Laden würden wir dann einfach per unserialize() aus dem String unsere Variable zurück generieren.
Um dies umsetzen zu können, müssten wir jetzt mit einem der obigen Verfahren zumindestens mehrere Strings in eine Datei legen und wie oben gezeigt adressieren.
Aber halt! Wir haben ja gelernt, daß mittels serialize() beliebige Variableninhalte in Strings konvertiert werden können. Warum sollten wir also nicht einfach die ganze Liste (also zum Beispiel ein Array) am Stück betrachten? Da Arrays immer im Speicher gehalten werden, ist die Suche in einem Array um Längen schneller erledigt, als direkt in einer Datei auf der Festplatte. Leider muss auf die Zeit zur Suche natürlich immer die Zeit zum Laden des kompletten Arrays in den Speicher dazu gerechnet werden.
Aber dazu später mehr. Für den Moment konzentrieren wir uns erst einmal auf den Code für unsere Basisoperationen:
- Speichern eines Datensatzes
- Lesen eines Datensatzes
- Verändern eines Datensatzes
- Löschen eines Datensatzes
- Finden eines Datensatzes
Grundsätzlich definieren wir alle Operationen ausschließlich auf der Kopie unserer Liste im Speicher. Vor Beginn einer Operation muss unsere Liste also in den Speicher geladen werden und nach einer Operation muss die Liste wieder als Datei ausgeschrieben werden.
Zuerst benötigen wir also die Operationen "ladeListe" und "schreibeListe":
| Php: |
<?php
/**
* Diese Funktion läd eine Liste aus einer Datei.
* @param String $dateiname Der Name der Datei mit den Daten
* @return array
*/
function ladeListe($dateiname)
{
// Prüfe auf Existenz und Lesbarkeit der Datendatei
return trigger_error(E_USER_ERROR, 'Die Datendatei ist nicht lesbar!');
// kompletten Dateiinhalt in den Speicher lesen:
// Dateiinhalt in Liste transformieren:
return trigger_error(E_USER_ERROR, 'Die Datendatei enthält keine Liste!');
return $daten;
}
/**
* Diese Funktion schreibt unsere Liste in eine Datei.
* @param String $dateiname Der Name der Datei mit den Daten
* @param array $liste die Liste
*/
function schreibeListe($dateiname,$liste)
{
// Prüfe Datei auf Existenz
{
return trigger_error(E_USER_ERROR, 'Die Datendatei existiert nicht und kann auch nicht angelegt werden.');
}else
{
// prüfe Dateiname auf Beschreibbarkeit
return trigger_error(E_USER_ERROR, 'Die Datendatei existiert, kann aber nicht beschrieben werden.');
}
// liste zu string transformieren
// String in Datei ablegen:
file_put_contents($dateiname,$daten);
}
?>
|
Zusätzlich muss die Liste einmalig für die Datei initialisiert werden, damit die beiden gezeigten Funktionen ihren Dienst tun können:
| Php: |
<?php
/**
* Diese Funktion bereitet eine Datei für die Verwendung als Listenspeicher vor.
* @param String $dateiname Der Name der Datei mit den Daten
*/
function initialisiere($dateiname)
{
schreibeListe ($dateiname, array());
}
?>
|
Und nun kommen wieder die Operationen. Hierbei ist zu beachten, daß die ersten beiden der o.g. Listenoperationen aus den Teiloperationen heraus verlagert werden sollten, falls mehrere dieser Teiloperationen in einem Skript durchgeführt werden sollen.
| Php: |
<?php
/**
* Diese Funktion hängt einen neuen Datensatz an die Datei an.
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $datum Ein Unixtimestamp
* @param String $inhalt Der Inhalt dieses Datensatzes
*/
function schreibe($dateiname, $datum, $inhalt)
{
// Liste aus Datei laden:
$liste=ladeListe($dateiname);
// Liste verändern:
$liste[]= array($datum, $inhalt);
// Liste zurück schreiben:
schreibeListe($dateiname,$liste);
}
/**
* Diese Funktion liefert einen Datensatz zurück oder False falls dieser nicht existiert.
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
* @return array/false
*/
function lese($dateiname,$ordnungsnummer)
{
// Liste aus Datei laden:
$liste=ladeListe($dateiname);
// Prüfen ob DS existiert:
if(! (isset($liste[$ordnungsnummer]) && is_array($liste[$ordnungsnummer])))
return false;
// DS zurück geben
return $liste[$ordnungsnummer];
}
/**
* Diese Funktion ersetzt einen durch die Ordnungsnummer identifizierten Datensatz
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
* @param integer $datum Ein neuer Unixtimestamp
* @param String $inhalt Der neue Inhalt dieses Datensatzes
*/
function ersetze($dateiname,$ordnungsnummer,$datum,$inhalt)
{
// Liste aus Datei laden:
$liste=ladeListe($dateiname);
// Liste verändern:
$liste[$ordnungsnummer]= array($datum, $inhalt);
// Liste zurück schreiben:
schreibeListe($dateiname,$liste);
}
/**
* Diese Funktion löscht einen durch die Ordnungsnummer identifizierten Datensatz
* @param String $dateiname Der Name der Datei mit den Daten
* @param integer $ordnungsnummer Die Ordnungsnummer des Datensatzes
*/
function loesche($dateiname,$ordnungsnummer)
{
// Liste aus Datei laden:
$liste=ladeListe($dateiname);
// Prüfen ob DS existiert:
if(isset($liste[$ordnungsnummer]))
{
// Liste verändern:
unset($liste[$ordnungsnummer]);
// Liste zurück schreiben:
schreibeListe($dateiname,$liste);
}
}
/**
* Diese Funktion sucht einen Datensatz in einer Datei und liefert seine Nr zurück oder false.
* @param String $dateiname Der Name der Datei mit den Daten
* @param String $wo Wo soll gesucht werden ('datum' oder 'inhalt')
* @param Mixed $was was soll gesucht werden
* @return Integer/false
*/
function suche($dateiname,$wo,$was)
{
// $wo in Ordnungsnummer übersetzen:
$translation= array('datum'=> 0, 'inhalt'=> 1);
if(! isset($translation[$wo]))
return trigger_error(E_USER_ERROR, 'Der Suchschlüssel existiert nicht.');
// Liste aus Datei holen
$liste=ladeListe($dateiname);
// Ordnungsnummer finden:
foreach($liste as $i=>$ds)
if($ds[$translation[$wo]]==$was)
return $i;
// wenn wir hier ankommen wurde kein passender DS gefunden
return false;
}
?>
|
Wie man sehen kann, sind die einzelnen Operationen relativ übersichtlich geraten. Hauptursache dafür sind die vielfältigen Methoden zum Array-Handling, die PHP sowieso schon mitbringt. Dieses Maß an Übersicht bedeutet aber nicht, daß die gezeigten Operationen sonderlich performant wären. Stellen wir uns nur einmal vor, unsere Liste hätte mehrere tausend Einträge, so müssten wir diese Einträge ja immer zwei mal alle betrachten, bevor und nachdem wir unsere Datensatzoperationen überhaupt angehen können.
Daraus resultiert in fast schon zwingender Logik, daß sich die hier vorgestellte Variante hauptsächlich dann eignet, wenn Daten a) in überschaubarerer Menge vorliegen, und sich b) nur selten verändern. Zusätzlicher Nachteil dieser Methode ist, daß keine andere Sprache das Stringformat im Datenspeicher versteht. Soll also aus Projekten in anderen Sprachen auf die selben Daten zugegriffen werden, dann macht diese Methode wenig Sinn.
Eine OOP-Version dieser Methode wurde z.B. in diesem Codeschnipsel verwendet.
|
|
| Nach oben |
|
 |
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
Powered by phpBB © 2001, 2005 phpBB Group Deutsche Übersetzung von phpBB2.de
|