Posts mit dem Label Verzeichnisse werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Verzeichnisse werden angezeigt. Alle Posts anzeigen

Donnerstag, 7. August 2008

Einlesen grosser Verzeichnisse ohne ADIR() / Reading large directories without ADIR()

Im UT kam heute die Frage bzgl. des Einlesens von Dateien aus Verzeichnissen mit mehr als 12800 Dateien auf. ADIR() lieferte einen Error 31 - Invalid subscript reference.

U.a. für solche Fälle steht in Foxpro die Funktion SYS(2000, Skeleton [, 1]) zur Verfügung. Mit ihrer Hilfe können Verzeichnisse über eine Verarbeitungsschleife eingelesen werden. Im folgenden ein kleines Beispiel das sämtliche EXE-Dateien aus dem Windowsverzeichnis zur Anzeige bringt.


LOCAL lcCurDir as String, lcWinDir as String, lcFile as String

lcCurDir = FULLPATH(CURDIR())
lcWinDir = GETENV([windir])

CHDIR (lcWinDir)

lcFile = SYS(2000,[*.exe])

IF !EMPTY(lcFile)
  CLEAR
  ?lcFile
  DO WHILE .T.
      lcFile = SYS(2000,[*.exe],1)
      IF !EMPTY(lcFile)
          ?lcFile
      ELSE
          EXIT
      ENDIF
  ENDDO
ENDIF

CHDIR (lcCurDir)
RELEASE lcCurDir, lcWinDir, lcFile

Montag, 30. Juni 2008

Kopieren, verschieben und löschen von Verzeichnisstrukturen / Copy, move and delete directory structures

Das Kopieren, Verschieben/Umbenennen und Löschen von einzelnen Dateien stellt unter Visual Foxpro üblicherweise kein Problem dar. Die Befehle


COPY FILE Filename1 TO Filename2
RENAME Filename1 TO Filename2
DELETE FILE Filename [RECYCLE]

übernehmen diese Aufgaben. An dieser Stelle möchte ich jedoch nochmals auf meinen Blog-Eintrag zum Thema Namensausdrücke hinweisen, denn die dort beschriebenen Vorgehensweisen gelten auch für die o.a. Befehle. Der Sourcecode sollte somit in etwa wie folgt ausschauen:


COPY FILE (cFilename1) TO (cFilename2)
RENAME (cFilename1) TO (cFilename2)
DELETE FILE (cFilename) RECYCLE

Im aktuellen Posting soll es sich aber nicht um einzelne Dateien sondern um komplette Verzeichnisse und Verzeichnisstrukturen drehen.
Um solche Aufgaben zu erledigen, steht uns die Script-Laufzeitbibliothek zur Verfügung. Hierbei handelt es sich um eine einzelne DLL mit dem Namen scrrun.dll die von Microsoftseite üblicherweise von den folgenden Anwendungen installiert wird: Windows Scripting Host, VBScript, Internet Explorer, Office.

In einem früheren Posting habe ich das FileSystemObject (FSO) bereits genutzt um diverse Laufwerksinformationen abzurufen. Damit sind die verfügbaren Möglichkeiten dieses Objektes jedoch noch nicht erschöpft. Bspw. stehen dort auch Funktionen zur Verfügung, welche wie die bereits oben beschriebenen VFP Befehle, das Kopieren, Umbenennen und Löschen einzelner Dateien ermöglichen. Auch das Erstellen, Lesen und Schreiben von Textdateien ist möglich, doch solche Funktionen nutze ich dann doch lieber mit VFP-Bordmitteln.

Wer sich intensiver mit dem FSO befassen möchte, dem steht u.a. dieser zugegebenermassen schon etwas ältere Technet-Artikel zur Verfügung:
http://www.microsoft.com/germany/technet/datenbank/articles/600360.mspx

Hier gibts die Seite im PDF-Format:
http://download.microsoft.com/download/a/3/3/a3393bf9-cfb4-45d9-ab90-772c81884d9b/sas_adm_nize.pdf

Nun zum eigentlichen Thema. Das FSO stellt uns u.a. drei Methoden zur Verfügung, mit deren Hilfe wir Ordner bearbeiten können.

Mit oFSO.CopyFolder werden komplette Verzeichnisstrukturen kopiert. oFSO.MoveFolder verschiebt Verzeichnisse und oFSO.DeleteFolder löscht sie. Nun ja, die sprechenden Funktionsnamen lassen ohne weiteres den Rückschluss auf ihre jeweilige Funktion zu. Der Hinweis an dieser Stelle ist sozusagen rein obligatorisch... ;-)

Der Einsatz der drei Methoden ist recht unspektakulär, solange wir darauf achten, dass wir Verzeichnisnamen nicht mit einem Backslash (\) abschliessen. In einem solchen Fall reagiert die DLL nämlich leicht verschnupft. Dies ist auch der Grund, weswegen im u.a. Code die etwas unsinnig wirkende Kombination von JUSTPATH und ADDBS Verwendung findet. Sie stellt letztlich sicher, dass grundsätzlich ein Backslash vorhanden ist, damit dieser problemlos entsorgt werden kann.

Noch eine Anmerkung: Der Einsatz von Wildcards (*) ist zwar von FSO-Seite möglich, wird im u.a. Beispielcode jedoch nicht berücksichtigt.


FUNCTION CopyFolder as Boolean
LPARAMETERS vSrcDir as String, vTgtDir as String
   LOCAL oFSO as Object, llOverwrite as Boolean, llReturn as Boolean
   llReturn = .F.
   * // Prüfen ob es das Quellverzeichnis gibt
   IF DIRECTORY(m.vSrcDir)
       * // Prüfen ob es da Ziellaufwerk gibt.
       * // (Ordner kann das FSO erzeugen, aber mit Laufwerken
       * // gibt es da schon noch das ein oder andere Problem) ;-)
       IF DIRECTORY(JUSTDRIVE(m.vTgtDir))
           m.vSrcDir    = JUSTPATH(ADDBS(m.vSrcDir))
           m.vTgtDir    = JUSTPATH(ADDBS(m.vTgtDir))
           llOverWrite    = .T.
           oFSO        = CREATEOBJECT([Scripting.FileSystemObject])
           oFSO.CopyFolder(m.vSrcDir, m.vTgtDir, llOverwrite)
       ENDIF
   ENDIF
   oFSO = []
   RELEASE oFSO
   IF DIRECTORY(m.vTgtDir)
       llReturn = .T.
   ENDIF
   RETURN llReturn
ENDFUNC

FUNCTION MoveFolder as Boolean
LPARAMETERS vSrcDir as String, vTgtDir as String
   LOCAL oFSO as Object, llReturn as Boolean
   llReturn = .F.
   * // Prüfen ob es das Quellverzeichnis gibt
   IF DIRECTORY(m.vSrcDir)
       * // Zum Einen prüfen ob es da Ziellaufwerk gibt.
       * // (Ordner kann das FSO erzeugen, aber mit Laufwerken
       * // gibt es da schon noch das ein oder andere Problem) ;-)
       * // zum Anderen sicherstellen, dass es das Zielverzeichnis
       * // noch nicht gibt. Andernfalls würde dessen Inhalt
       * // überschrieben werden...
       IF DIRECTORY(JUSTDRIVE(m.vTgtDir)) ;
       AND !DIRECTORY(m.vTgtDir)
           m.vSrcDir    = JUSTPATH(ADDBS(m.vSrcDir))
           m.vTgtDir    = JUSTPATH(ADDBS(m.vTgtDir))
           oFSO        = CREATEOBJECT([Scripting.FileSystemObject])
           oFSO.MoveFolder(m.vSrcDir, m.vTgtDir)
           IF DIRECTORY(m.vTgtDir)
               llReturn = .T.
           ENDIF
       ENDIF
   ENDIF
   oFSO = []
   RELEASE oFSO
   RETURN llReturn
ENDFUNC

FUNCTION DeleteFolder as Boolean
LPARAMETERS vTgtDir as String
   LOCAL oFSO as Object, llReturn as Boolean, llForceDel as Boolean
   llReturn = .T.
   * // Prüfen ob es das Verzeichnis gibt
   IF DIRECTORY(m.vTgtDir)
       m.vTgtDir    = JUSTPATH(ADDBS(m.vTgtDir))
       llForceDel    = .T.
       oFSO        = CREATEOBJECT([Scripting.FileSystemObject])
       oFSO.DeleteFolder(m.vTgtDir, llForceDel)
   ENDIF
   oFSO = []
   RELEASE oFSO
   IF DIRECTORY(m.vTgtDir)
       llReturn = .F.
   ENDIF
   RETURN llReturn
ENDFUNC

Montag, 21. April 2008

Arbeiten mit Verzeichnissen und Dateinamen (Teil 3) / Working with directories and filenames (Part 3)

Die beiden vorangegangenen Teile handelten von den Funktionen GETDIR() und ADDBS() sowie GETFILE(), CHDIR und CURDIR(). In diesem Eintrag geht es nun um die Zerlegung der einzelnen Bereiche eines Dateinamens inklusive vorgelagertem Pfadnamen.

Wenn wir mit Hilfe von GETFILE() eine Datei selektiert und die Auswahl überprüft haben,

cFile = GETFILE()
IF FILE(cFile)
    ...
ENDIF

kommt es immer wieder vor, dass wir nur einen Teil des in 'cFile' stehenden Wertes verarbeiten möchten.

Gehen wir einmal davon aus, dass in cFile der folgende Wert enthalten ist:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc
 
so stellt uns Visual Foxpro nun u.a. sieben Funktionen bereit, diesen String zu zerlegen.
Die Funktion JUSTDRIVE() liefert uns als Ergebnis den Laufwerksbuchstaben:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?JUSTDRIVE(cFile)

Die Funktion JUSTPATH() liefert uns als Ergebnis den Laufwerksbuchstaben inklusive des kompletten Pfades, jedoch ohne Backslash am Ende:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?JUSTPATH(cFile)

Die Funktion JUSTSTEM() liefert uns als Ergebnis den Dateinamen ohne Suffix:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?JUSTSTEM(cFile)

Die Funktion JUSTFNAME() liefert uns als Ergebnis den Dateinamen mitsamt dem Suffix:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?JUSTFNAME(cFile)

Die Funktion JUSTEXT() liefert uns als Ergebnis nur das Suffix:

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?JUSTEXT(cFile)

Mit Hilfe dieser Funktionen können wir den Datei- bzw. Verzeichnisnamen in 5 Segemente zerlegen und ggf. durch neue Teile ersetzen. Wollen wir nun bspw. eine Backup-Datei von Demodatei.doc im selben Verzeichnis anlegen, dann greift die Funktion FORCEEXT(). Mit ihrer Hilfe wird aus Demodatei.doc der String Demodatei.bak Hierbei steht es uns frei, den kompletten Verzeichnisnamen oder nur den reinen Dateinamen mitzugeben.

cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?FORCEEXT(cFile,[bak])
?FORCEEXT(JUSTSTEM(cFile),[bak])
?FORCEEXT(JUSTFNAME(cFile),[bak])


Soll die Backup-Datei in einem Unter- oder Parallelordner abgelegt werden, so könnte die Funktion FORCEPATH() zum Zuge kommen.

Für den Unterordner 'Backups':

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Backups\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?FORCEPATH(cFile,ADDBS(JUSTPATH(cFile)) + [Backups])

Im Parallelordner 'Backups':

C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Backups\Demodatei.doc
 
cFile = [C:\Dokumente und Einstellungen\Benutzername\Lokale Einstellungen\Temp\Demodatei.doc]
?FORCEPATH(cFile,ADDBS(JUSTPATH(JUSTPATH(cFile))) + [Backups])

Im Verbund mit der Funktion FORCEEXT() ergeben sich daraus nun bspw. die folgenden Funktionen:

LOCAL    lcBackupExt as String, lcBackupPath as String, ;
    cFile as String, cFNew as String, cSubDir as String, cParall as String
       
lcBackupExt     = [bak]
lcBackupPath    = [Backups]
cFile           = GETFILE()
cFNew           = FORCEEXT(JUSTSTEM(cFile),lcBackupExt)
cSubdir         = GetSubdirectory(JUSTPATH(cFile),lcBackupPath,.T.)
cParall         = GetParallelDirectory(JUSTPATH(cFile),lcBackupPath,.T.)

CLEAR

=CreateBackupFile(cFile,cSubDir + cFNew)
=CreateBackupFile(cFile,cParall + cFNew)

FUNCTION CreateBackupFile
LPARAMETERS vSourceFile as String, vTargetFile as String

    LOCAL llReturn as Boolean
   
    ?[kopiere ] + vSourceFile
    ?[nach    ] + vTargetFile
    TRY
        COPY FILE (m.vSourceFile) TO (m.vTargetFile)
        ?[Kopiervorgang erfolgreich durchgeführt]
        llReturn = .T.
    CATCH
        ?[Kopiervorgang ist fehlgeschlagen]
    ENDTRY

    RETURN llReturn
   
ENDFUNC

FUNCTION GetSubdirectory
LPARAMETERS vPath as String, vSubDir as String, vCreate as Boolean

    LOCAL lcPath as String
    m.vPath    = ADDBS(m.vPath)
    lcPath     = FORCEPATH(m.vPath,m.vPath + m.vSubDir)
   
    IF m.vCreate = .T. AND !DIRECTORY(lcPath)
        MKDIR (lcPath)
    ENDIF
   
    RETURN lcPath
   
ENDFUNC

FUNCTION GetParallelDirectory
LPARAMETERS vPath as String, vSubDir as String, vCreate as Boolean

    LOCAL lcPath as String
    lcPath    = ADDBS(ADDBS(JUSTPATH(JUSTPATH(ADDBS(m.vPath)))) + m.vSubDir)

    IF m.vCreate = .T. AND !DIRECTORY(lcPath)
        MKDIR (lcPath)
    ENDIF

    RETURN lcPath
   
ENDFUNC

Freitag, 4. April 2008

Arbeiten mit Verzeichnissen und Dateinamen (Teil 2) / Working with directories and filenames (Part 2)

Nachdem ich im ersten Teil auf die Befehle GETDIR() und ADDBS() näher eingegangen bin, ist dieses Mal die Auswahl von Dateien angesagt.
Ergänzend möchte ich auf einen älteren Eintrag hinweisen, der die Arbeit mit Namensausdrücken zum Thema hat.
Der Befehl zur Dateiselektion ist sicherlich jedem VFPler hinlänglich bekannt:
cFile = GETFILE()

GETFILE() kann jedoch mit diversen Parametern versorgt werden, die u.a. auch eine genauere Bestimmung der aufgelisteten Dateien beinhaltet.
GETFILE([cFileExtensions] [, cText] [, cOpenButtonCaption] [, nButtonType] [, cTitleBarCaption])

Parameter 1 (der komplexeste der 5) befasst sich mit den auswählbaren Dateitypen. Hierbei ist unbedingt auf die richtige Syntax innerhalb der Stringdefinition zu achten.
Grundsätzlich gilt:
  • Die einzelnen Parameter werden durch Kommata von einander getrennt
  • Parameter 1 wird als String übergeben und steht somit in Anführungszeichen/Hochkommata/eckigen Klammern
  • Innerhalb von Parameter 1 erfolgt die Trennung der einzelnen Auswahlblöcke mit einem Semikolon.
  • Innerhalb der einzelnen Blöcke erfolgt die Trennung von beschreibendem Text und Suffix über einen Doppelpunkt.
  • Innerhalb der Suffixauflistung erfolgt die Trennung der einzelnen Suffixe mit einem Komma.
cFile = GETFILE([Fotos jpg,gif,png,bmp):jpg,gif,png,bmp;] ;
     + [Dokumente(doc,txt,xls,pdf):doc,txt,xls,pdf], ;
       [Dateiname], ;
       [Auswählen], ;
       0, ;
       [Bitte wählen Sie ein Dokument aus])

In obigen Beispiel stellen wir standardmäßig die Fotoauswahl für die Dateitypen JPG, GIF, PNG und BMP bereit. Innerhalb der Combobox 'Dateityp' wird dieser Punkt als Voreinstellung eingeblendet. Innerhalb der Auswahl taucht jedoch auch die Möglichkeit auf, gezielt nach Dokumenten ausschau zu halten (DOC, TXT, XLS, PDF)

Wichtig bei der Funktion GETFILE() ist, dass wir zuvor in das Startverzeichnis unserer Wahl gewechselt haben sollten.
Ein Wechsel erfolgt üblicherweise mit dem Befehl
CD | CHDIR

Damit wir anschliessend wieder in unser ursprüngliches Verzeichnis zurückspringen können sollte der aktuelle Pfad zwischengespeichert werden.
cCurDir = CURDIR()
CHDIR (cDir)
cFile = GETFILE()
....
CHDIR (SYS(5) + cCurDir)
RELEASE cCurDir

An dieser Stelle sei angemerkt, dass es durchaus sinnvoll ist, sofort nach dem Programmstart das Arbeitsverzeichnis der APP/EXE in einer zentral verfügbaren Eigenschaft oder Variablen zu speichern. Dies kann bspw. über eine Anbindung an das _screen-Objekt erfolgen:
_screen.ADDOBJECT([oVerz],[custom])
_screen.oVerz.AddProperty([Startpfad],ADDBS(SYS(5) + SYS(2003)))

Vorteil dieser Vorgehensweise ist, dass wir ein jederzeit verfügbares und erweiterbares Verzeichnisobjekt haben, in dem wir alle möglichen Ordner gezielt hinterlegen und jederzeit abfragen können. Hierdurch verändert sich natürlich auch der zuvor gezeigte Code.
CHDIR (cDir)
cFile = GETFILE()
....
CHDIR (_screen.oVerz.Startpfad)

Donnerstag, 27. März 2008

Arbeiten mit Verzeichnissen und Dateinamen (Teil 1) / Working with directories and filenames (Part 1)

Visual Foxpro ist eine Entwicklungssprache, bei der man sich nicht über einen Mangel an Befehlen und Funktionen beschweren kann. Ganz im Gegenteil. Problematisch ist es allerdings schon, in diesem Befehlsdschungel so halbwegs den Überblick zu bewahren.

Verständlich, dass der ein oder andere lieber auf die wenigen Befehle zurückgreift, die er oder sie bereits seit vielen Jahren immer wieder einsetzt. Schade eigentlich, denn gerade im Bereich der Manipulation von Strings hat der Fux einiges zu bieten.

Dieser und die nächsten Einträge befassen sich mit dem Umgang mit Verzeichnissen und Dateinamen. Hier stehen eine Vielzahl von Funktionen zur Verfügung, die uns viel Fummelei abnehmen.

Das Auswählen eines Verzeichnisses ist sicherlich allen hinlänglich bekannt.

cDir = GETDIR()

Optional stellt GETDIR() jedoch diverse zusätzliche Parameter bereit:

GETDIR([cDirectory [, cText [, cCaption [, nFlags [, lRootOnly]]]]])

Parameter 1 nimmt ein Startverzeichnis auf, in dem die Auswahl beginnen soll
Parameter 2 nimmt einen erklärenden Text auf
Parameter 3 nimmt eine individuelle Caption auf
Parameter 4 nimmt Flags auf, die von ihrer Wertigkeit additiv übergeben werden
Parameter 5 setzt fest, ob übergeordnete und/oder parallele Ordner aufgerufen werden können

cDir = GETDIR([C:\TEMP\],[Bitte wählen Sie einen Ordner aus], [Ordnerauswahl], 1+2+8+16+32+64+16384, .T.)

Nach erfolgreicher Auswahl steht in cDir nun u.U. folgendes:

c:\temp\unterordner1\

Wichtig hierbei ist, dass unserem Verzeichnis bereits ein Backslash (\) angehängt wurde.
Können wir uns nicht darauf verlassen, ob eine bestimmte Funktion einen Pfadnamen inklusive Backslash am Ende liefert, so stehen uns diverse Möglichkeiten offen, diesen ergänzen.

Variante 1 (Für alle mit einem gesunden Gottvertrauen ;-) )

cDir = cDir + [\]

Variante 2 (nicht falsch aber viel zu umständlich)

cDir = cDir + IIF(RIGHT(cDir,1) = [\],[],[\])

Variante 3 (Die Richtige!!)

cDir = ADDBS(cDir)

INFO: ADDBS() hängt nur im Bedarfsfall einen Backslash an den übergebenen String. Wir müssen uns also keine Gedanken darüber machen, ob bereits einer vorhanden ist oder nicht.