phpbar.de logo

Mailinglisten-Archive

[php] speicher =?iso-8859-1?Q?l=F6schen=3F?=

[php] speicher =?iso-8859-1?Q?l=F6schen=3F?=

Ulf Wendel ulf_(at)_redsys.de
Wed, 26 Jan 2000 20:05:02 +0000


Pascal Schult wrote:

> jezt soll ein script ein verzeichnis öffnen, dies auslesen und nach-
> einander die enthaltenen files öffnen, auslesen in einen string packen
> und dann in ein neues file in einem anderen verzeichnis schreiben.
> klappt auch wunderbar. jedoch schafft dieses script nur ca. 6 files

Da fragt man sich natürlich, warum Du kein Systemkommando benutzt... 

> hmm, laeuft hier auf nem wxmp (win98, xitami, mysql, php3.11)

Bei mir ist es gerade die Kommandozeile mit einem 3.0.11.

> aber soweit kommt es nicht. flush() ist doch nur dafür da, daß alles an
> den browser übergeben wird, schon bevor das script fertig ist, oder?

Ja. Und damit ist es super geeignet Statusmeldungen auszugeben, bevor
das Skript eines Todes stirbt.

> mails in dieser liste, aber hier der quellcode:

Puh, den will ich auch gar nicht mehr sehen. Laß uns noch mal ganz vorne
anfangen. 
Aufgabe: kopiere alle Files eines Quellverzeichnisses in ein
Zielverzeichnis.

Bei kleineren Aufgaben beginne ich gleich mit dem Hauptprogramm. Ich
schreibe auf, wie mein Programm aussehen soll. Dabei verwende ich
Funktionen, die es noch gar nicht gibt. Ich mache mir also ein Bild der
Legosteine, die ich gerne hätte. An den Code spiele ich so lange, bis
ich ein Gefühl dafür habe, welche Legosteine mir die Arbeit besonders
gut erleichtern könnten.

<?php
$source_dir = "f:/tmp/tmp/";        # Quellverzeichnis
$dest_dir = "f:/tmp/tmp/new/";      # Zielverzeichnis

$files = get_files($source_dir);    # Dateien im Quellverzeichnis
ermitteln

if (!is_array($files) || 0==count($files))
  exit;

$status = array();
reset($files);
while (list(, $file)=each($files)) {
  $source = $source_dir.$file;      # Quelldatei
  $dest = $source_dir.$file;        # Zieldatei
  out(file_copy($source, $dest));   # kopieren
}
?>

Hier wurden drei Legosteine eingeführt:

array get_files( string $dirname ) 
string file_copy ( string $source, string $dest)
void out ( string $text )

Die Funktion get_files() muß zunächst überprüfen, ob sie mit dem Namen
eines Verzeichnisses aufgerufen wurde (is_dir()). Danach wird das
Verzeichnis ausgelesen. Verzeichniseinträge vom Typ file (is_file)
werden in einem Array gespeichert, alle anderen werden ignoriert. Dies
verhindert, daß beim späteren kopieren versucht wird Directories, Links
und ähnliches zu verarbeiten.

<?php 
// array get_files ( string $dirname )
function get_files($dirname) {

  if (!is_dir($dirname))
    return false;

  $h = opendir($dirname);
  if (!$h)
    return false;

  $files = array();
  while ($file = _(at)_readdir($h))
    if (is_file($dirname.$file))
      $files[$file] = $file;

  return $files;
} // end func get_files
?>

file_copy() ist recht gesprächig. An fast jeder Stelle an der ein Fehler
abgefangen werden kann, wird dies gemacht und die Funktion mit einer
Fehlermeldung beendet.
Anders als im Originalskript wurde in diesem Beispiel fread() benutzt.
Immer, wenn man alle Inhalte aus einer Datei benötigt und auf eine
zeilenweise Verarbeitung verzichten kann sollte fread() benutzt werden.
fread() ist erheblich schneller, als das zeilenweise einlesen.
unset() wird überhaupt nicht benutzt, weil mit lokalen Variablen
gearbeitet wird und sich PHP um die Speicherfreigabe kümmert.

<?php
// string file_copy ( string $source, string $dest )
function file_copy($source, $dest) {

  if (""==$source || ""==$dest)
    return "Quelle oder Ziel nicht angegeben";

  if (!file_exists($source))
    return "Quelldatei '$source' existiert nicht";

  if (file_exists($dest) && !is_writeable($dest))
    return "Zieldatei existiert und kann nicht überschrieben werden";

  $fh = _(at)_fopen($source, "r");
  if (!$fh)
    return "Quelldatei '$source' kann nicht gelesen werden";
  $daten = fread($fh, filesize($source));
  fclose($fh);

  $fh = _(at)_fopen($source, "w");
  if (!$fh)
    return "Zieldatei '$dest' kann nicht geöffnet werden";
  if (!_(at)_fwrite($fh, $daten))
  	return "In der Zieldatei '$dest' konnten keine Daten gespeichert
werden";
  fclose($fh);

  return "";
} // end func file_copy
?>

out() letztlich ist für die Ausgabe von Meldungen zuständig.
Normalerweise wartet PHP mit der Ausgabe von Text bis das Ende des
Skripts erreicht ist. Manchmal will man jedoch schon vorher
Statusmeldungen sehen, um zu erfahren welcher Programmteil verarbeitet
wird. Dies ist auch sehr wichtig bei langen Laufzeiten, damit der
Browser keinen Timeout meldet. flush() leert den Ausgabepuffer und
schickt die Daten direkt an den Client.

function out($text) {
  echo "$text<br>\n";
  flush()
}

it obigen Snippets kann man zwar ein übersichtliches Programm schreiben,
aber kein gutes. Das Programm setzt vorraus, daß während der gesamten
Laufzeit keine Änderungen an den Verzeichnissen vorgenommen werden.
Besser wäre es, den Ablauf zu verändern und Filelocking zu benutzen
(flock()):

- öfffne Verzeichnis 

- lese Eintrag
- verarbeite Eintrag 

- schließe Verzeichnis


Noch besser ist es, die Systemfunktionen mit einem copy zu
beauftragen...
Und warum war das alte Skript jetzt abgestürzt. Ich tippe mal, daß es
nicht erlaubt ist im Windows Desktopverzeichnis zu werkeln.

Ulf


php::bar PHP Wiki   -   Listenarchive