PDF ansehen - Access [basics]

Transcription

PDF ansehen - Access [basics]
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
Zippen mit Bordmitteln
Das VBA-gesteuerte Packen und Archivieren von Dateien ist eine Aufgabe, der auch Access-Entwickler immer wieder begegnen. Dass man dabei keineswegs auf externe Komponenten oder Hilfsmittel angewiesen ist und mit Windows-Bordmittel auskommen kann, soll dieser Beitrag zeigen.
Beispieldatenbank
Die Beispiele dieses Artikels finden
Sie in der Datenbank 1502_Zippen.
mdb.
Zip-Format
Es gibt zweifellos Alternativen zum
altehrwürdigen Zip-Format, denn
RAR oder 7z etwa bieten erheblich
bessere Kompressionsraten an.
Doch diese Formate setzen voraus,
dass auf dem System ein entsprechendes Archivierungsprogramm
installiert ist, und bei Weitergabe
einer solchen Archivdatei können
Sie nicht einfach davon ausgehen,
dass dies beim Adressaten der Fall
ist. Mit dem Zip-Format sind Sie auf
der sicheren Seite: Windows hat seit
einigen Generationen einen entsprechenden Support eingebaut. Über
den Explorer lassen sich Zip-Dateien
wie Ordner behandeln, einsehen und
bearbeiten. Und was sich manuell erledigen lässt, sollte sich über irgendeinen Weg auch programmtechnisch
realisieren lassen.
Shell-Funktionen
Die übliche Herangehensweise, wenn
Funktionen von Windows gefragt
sind, ist die Suche im API-Katalog. In
unserem Fall kann darauf verzichtet
werden, da Windows mit der ShellBibliothek eine COM-Schnittstelle
zur Verfügung stellt, die alles Nötige
mitbringt. Es handelt sich um die
shell32.dll im Systemverzeichnis,
www.access-basics.de
welche sich in der Liste der Verweise
von VBA namentlich als Microsoft
Shell Controls And Automation
ausgibt. Nachdem Sie die Bibliothek
ihrem Projekt über den Verweisedialog hinzugefügt haben, finden Sie
deren Klassen im Objektkatalog,
wenn Sie links oben den Eintrag
Shell32 auswählen (Bild 1). An den
Klassenbezeichnungen, wie Folder,
FolderItem und ShellFolderView,
lässt sich bereits ablesen, dass es
hier zuvörderst um Verzeichnisse und
deren Inhalte geht. Da die Shell, wie
erwähnt, eine Zip-Datei als Verzeichnis ansieht, wäre nun zu erläutern,
wie man so ein Verzeichnis anspricht.
Dazu gehen Sie vom Hauptobjekt
der Bibliothek aus, der Shell-Klasse,
welche in der Abbildung bereits
markiert ist.
Eine Instanz dieser Klasse erhalten
Sie einfach über die New-Zuweisung
an eine Objektvariable:
Dim objShell As New Shell32.Shell
Hier sollte nicht unerwähnt bleiben,
dass die ganze Angelegenheit auch
komplett ohne einen Bibliotheksverweis auskäme. Folgender Ausdruck
erzeugt nämlich ebenfalls das ShellObjekt:
Dim objShell As Object
Set objShell = _
CreateObject("Shell.Application")
Bild 1: Die Shell32-Bibliothek, im VBAObjektkatalog dargestellt
Haben Sie nun das Hauptobjekt, so
können Sie sogleich allerlei Methoden desselben ansprechen. So öffnet
etwa die Methode objShell.FileRun
den Ausführen-Dialog von Windows,
oder TrayProperties den Dialog zu
Einstellungen der Taskleiste. Warum Microsoft ausgerechnet solche
Funktionen in die COM-Schnittstelle
verbaute, ist nicht recht nachvollzieh-
Seite 3
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
bar, da man sie programmgesteuert
wohl höchst selten aufrufen wird. Sie
interessieren uns auch nicht weiter.
Lediglich die Funktion NameSpace
ist für unsere Belange wichtig: sie
allein gibt ein Folder-Objekt, also ein
Verzeichnis, zurück. Dazu übergibt
man ihr als Parameter den Verzeichnisnamen:
::{21EC2020-3AEA-1069-A2DD-
Dim objItm As FolderItem
08002B30309D}
For Each objItm in objFolder.Items
Diese GUID symbolisiert einen virtuellen Ordner. Machen Sie die Probe
aufs Exempel und setzen diese GUID
als String für den Pfadnamen ein:
Next objItm
Debug.Print objItm.Name
? objShell.NameSpace("::{21EC20203AEA-1069-A2DD-08002B30309D}").Title
Dim objFolder As Shell32.Folder
Set objFolder = objShell.NameSpace ( _
"c:\windows")
Auf den Methodennamen NameSpace würde man wahrscheinlich
nicht kommen und eher so etwas
wie GetFolder erwarten. Grund für
die Bezeichnung ist, dass sie eben
nicht nur physische Verzeichnisse
ermittelt, sondern auch virtuelle, wie
dies beim Zip-Archiv vorliegt. Statt
des Verzeichnispfads nimmt sie etwa
auch Zahlen entgegen. Versuchen
Sie dies:
? objShell.NameSpace(0).Title
Ergebnis wäre der String Desktop.
(Title ist die Methode zum Auslesen
der Bezeichnung eines Folder-Objekts.) Der komplette Pfadname ist
etwas umständlicher zu ermitteln:
? objShell.NameSpace(0).Self.Path
Das ergibt etwa C:\Users\André\
Desktop. Sie können nun mit den
Zahlenparametern experimentieren.
Übergeben Sie die 3, so erhalten Sie
als Bezeichnung Systemsteuerung.
Tatsächlich lässt sich die Systemsteuerung ja im Explorer-Baum anzeigen. Was aber ist deren Pfad? Sie
erhalten den Ausdruck
www.access-basics.de
Auch das geht und liefert uns abermals die Bezeichnung Systemsteuerung.
Zusammengefasst also nimmt
NameSpace als Parameter sowohl
Verzeichnis-Strings entgegen, wie
auch Zahlenwerte (die sogenannten
KnownFolder-IDs) und schließlich
GUIDs (KnownFolder-CLSIDs) als
Strings.
Wenden wir uns nach diesem Ausflug in den Shell-Namespace wieder
den Zip-Archiven zu. Sie können
sicher erraten, wie eine Zip-Datei als
Folder-Objekt zu erhalten ist: Sie
übergeben einfach deren Dateinamen. Ein Beispiel:
Set objFolder = objShell.NameSpace ( _
"d:\beispiele\test.zip")
Als nächstes interessiert uns natürlich der Inhalt eines Ordners – in diesem Fall die enthaltenen Dateien. Die
Folder-Klasse sieht dafür die Auflistungs-Eigenschaft Items vor, welche
sich über eine For-Next-Schleife
durchlaufen lässt. Jedes Element
der Items-Auflistung ist vom Typ
FolderItem. Möchten Sie die Namen
der Dateien im Ordner ausgeben, so
käme etwa diese Routine infrage:
Auf diese Weise können Sie die in einem Zip-Archiv befindlichen Dateien
inspizieren. Dabei sollte noch erwähnt werden, dass das Archiv wiederum Ordner enthalten kann. Nur
dann weist die Eigenschaft IsFolder
des entsprechenden FolderItems den
Wert True auf, und die Eigenschaft
Type gibt einen Text aus, der genau
der Bezeichnung im Explorer entspricht. Je nach System kann diese
Bezeichnung allerdings unterschiedlich sein. Ist etwa ein Packprogramm
installiert, so könnte die Bezeichnung
WinRAR ZIP-Archiv lauten.
FolderItems extrahieren
Wie jedoch lassen sich die Dateien
oder Ordner des Archivs nun entpacken? Im Objektkatalog findet man
weder zum FolderItem, noch zum
Folder-Objekt Funktionsnamen, wie
Extract oder Uncompress, die dafür
dienlich sein könnten. Das aber ist
einleuchtend, da die Shell das Archiv
als normalen Ordner ansieht und somit lediglich jene Methoden anbietet,
die auch für Dateien eines Verzeichnisses gälten. Im Explorer können
Sie eine Datei aus dem Archiv extrahieren, indem Sie sie entweder per
Drag&Drop verschieben, oder indem
Sie sie kopieren und in einen anderen
Ordner einfügen. Genau das geht
auch hier über die CopyHere-Funktion eines Folder-Objekts. Diese
Methode erwartet als Parameter ein
Folder- oder FolderItem-Objekt. Der
Vorgang hat folgendermaßen auszusehen:
Seite 4
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
Sie setzen zuerst ein Folder-Objekt
auf das Zielverzeichnis. Dann benutzen Sie dessen CopyHere-Methode,
um in dieses Verzeichnis Dateien
oder Ordner zu kopieren, wobei
diese in Form von zuvor erzeugten
FolderItems daher kommen müssen.
Machen wir den Test und versuchen
das Archiv test.zip in einen Ordner
d:\testordner zu extrahieren:
Prozess asynchron arbeitet, ist er unter Umständen noch mit dem Kopieren eines Items beschäftigt, während
VBA bereits mit dem Code fortfährt –
die CopyHere-Methode wartet nicht
auf den Vollzug! Es hat sich gezeigt,
dass ohne ein DoEvents manchmal
Dateien unterschlagen werden.
Und tatsächlich: Im Zielordner laden
damit die Dateien des Archivs! Sollte
das Archiv Unterordner mit Dateien
enthalten, so werden auch diese
alle anstandslos entsprechend der
Struktur angelegt. Es ist also nicht
etwa nötig, diese Unterordner und
Dateien in der Routine alle einzeln
anzusprechen.
Bei umfangreicheren Archiven werden Sie feststellen, dass sich beim
Ausführen der Routine automatisch
der Windows-Fortschrittsdialog
öffnet. Das Shell-Objekt verhält sich
also exakt gleich, wie beim manuellen Kopieren von Dateien im Explorer.
In Maßen lässt sich das Verhalten
jedoch über einen zweiten optionalen
Parameter von CopyHere steuern,
den wir bisher unterschlagen haben.
Mit Options kann man eine Kombination von Steuerkonstanten übergeben, die Sie im Modul mdlZipShell
der Beispieldatenbank kommentiert
als Enumeration eFileOp finden. So
bewirkt etwa die Angabe von eOpNoProgress, dass sich eben kein
Fortschrittsdialog öffnet. Oder eOpAllowUndo weist an, dass die Operation wieder rückgängig gemacht
werden kann. In unserem Fall hieße
das, dass Sie im Explorer dann das
Rückgängig-Symbol betätigen könnten, wodurch sich das Zielverzeichnis
wieder leeren würde. Interessant ist
auch die Konstante eOpNewName.
Ohne deren Angabe würde eine existierende Datei mein.txt im Zielverzeichnis nicht überschrieben, sondern automatisch mit einem neuen
Namen kopiert; also etwa in Kopie
von mein.txt oder mein(1).txt.
Wichtig ist auch die Zeile mit der
DoEvents-Anweisung. Da der Shell-
Die komplette Routine zum Entpacken eines Zip-Archivs finden Sie
Dim objZiel As Folder
Set objZiel = objShell.NameSpace( _
"d:\testordner")
objZiel.CopyHere objZipFolder
Leider wird das Archiv damit nicht
entpackt, sondern nur eine Kopie
der Zip-Datei angelegt – eigentlich
klar, da das Objekt objZipFolder ja
das Archiv selbst kennzeichnet, nicht
dessen Inhalt. Folglich muss hier
die oben angeführte Routine zum
Auslesen der FolderItems modifiziert
werden:
Dim objItm As FolderItem
For Each objItm in objFolder.Items
objZiel.CopyHere objItm
DoEvents
Next objItm
www.access-basics.de
in der Beispieldatenbank unter der
Funktion UnZipFile. Sie übergeben
ihr einfach den Pfadnamen der ZipDatei und das Zielverzeichnis. Bei
erfolgtem Entpacken gibt die Funktion ein True zurück. Wie Sie sehen,
kommt man über die Shell-Bibliothek
mit nur wenigen Code-Zeilen zum
Ergebnis, und externe Zusatzkomponenten sind überflüssig.
Zip-Archive erzeugen
Zwar gibt uns Windows die Möglichkeit, Zip-Dateien zu entpacken, aber
das Anlegen solcher scheint nicht
vorgesehen zu sein. Ein Rechtsklick
auf den freien Bereich eines Ordners
im Explorer zeigt im Kontextmenü
unter Neu... keinen Eintrag für das
Erstellen eines Zip-komprimierten
Ordners. Tatsächlich gibt es keinerlei
Methoden in der Shell, um das zu
bewerkstelligen.
Zum Glück ist eine Zip-Datei prinzipiell eine ziemlich einfache Sache,
die sich auch über einen Workaround
anlegen lässt. Nehmen Sie eine beliebige Zip-Datei und löschen aus ihr
sämtliche Dateien. Das Archiv existiert dann immer noch, hat nun aber
eine Größe von nur 23 Byte. Dieses
Grundgerüst kann auch über VBA
angelegt werden:
Dim arrZip(22) As Byte
arrZip(0) = 80 'P
arrZip(1) = 75 'K
arrZip(2) = 5
arrZip(3) = 6
Sie legen ein Byte-Array an und füllen die ersten vier Elemente mit den
Vorgabewerten für eine Zip-Datei.
Die restlichen Bytes enthalten Nullen.
Seite 5
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
Das Array muss nun nur noch
in eine Datei gespeichert
werden:
Dim objZip As Shell32.Folder
Dim objSource As Folder
Dim objItem As FolderItem
Set objZip = objShell.NameSpace("d:\test\xy.zip")
Set objSource = objShell.NameSpace("d:\test\")
Set objItem = objSource.Items.Item("mein.txt")
objZip.CopyHere objItem
und CreateZipFromFolder.
Der ersten übergeben Sie als
Parameter den Pfadnamen der
zu erzeugenden Zip-Datei und
Open "d:\test\xy.zip" For Binary
alle hinzuzufügenden DateiAs #1
en in einem String-Array, der
Listing 1: Hinzufügen von Dateien zum Zip-Archiv
Put F, , arrZip
zweiten stattdessen nur den
Close #1
würde die Datei mein.txt des QuellPfadnamen eines Ordners, den
verzeichnisses d:\test\ über die VariSie im Archiv haben wollen. Beide
Im Testordner wird im Explorer jetzt
able objItem in das Archiv wandern.
Prozeduren werden vom Formular
für die Datei xy.zip die korrekte BefrmZipper verwendet, das eine Oberzeichnung Zip-Archiv angezeigt.
Sollten Sie in einer Schleife mehrere
fläche für sie bereitstellt.
Dateien in das Archiv übernehmen,
Das weitere Vorgehen können Sie
so sollten Sie auch hier ein DoEvents
Zippen über Formular
sich denken. Die angelegte Zip-Datei
einfügen. Sonst kommt es vor,
Bild 2 zeigt Sie das Formular frmZipwird über das Shell-Objekt als Folder
dass im Archiv anschließend einige
per der Beispieldatenbank nach dem
behandelt und über dessen CopyDateien fehlen. Auch sonst gilt, etwa
Öffnen. Im obersten Textfeld geben
Here-Methode Dateien hinzugefügt.
für die Optionen der CopyHere-MeSie den Pfadnamen der Zip-Datei an,
Eine rudimentäre Routine könnte so
thode, dasselbe, wie für die Routine
die Sie erzeugen wollen. Dafür könaussehen:
zum Entpacken des Archivs.
nen Sie auch die Schaltfläche rechts
daneben verwenden. Sie öffnet einen
Dim objZip As Shell32.Folder
Ausführlichere Routinen zum ErzeuDatei speichern-Dialog, in dem der
Dim objSource As Folder
gen von Zip-Archiven finden Sie in
Name AB_Test.zip auf das aktuelle
Set objZip = objShell.NameSpace( _
der Beispieldatenbank in Gestalt
Datenbankverzeichnis voreinge"d:\test\xy.zip")
der beiden Prozeduren CreateZip
stellt ist, wie in Bild 3. Diesen Dialog
Set objSource = objShell.NameSpace( _
"c:\windows\")
objZip.CopyHere objSource
Führen Sie diesen Code besser nicht
aus! Er kopiert den gesamten Inhalt
des Windows-Ordners in das ZipArchiv xy.zip. Deutlich machen soll er
nur, dass die Shell sich hier genauso
verhält, wie beim Entpacken. Komplette Ordnerstrukturen können mit
nur einer Zeile in ein Archiv verfrachtet werden.
Möchten Sie nur einzelne Dateien in
das Archiv übernehmen, so benötigen Sie statt des Forder-Objekts ein
FolderItem-Pendant. Eine Erweiterung der Routine käme etwa wie
in Listing 1 daher (Ausschnitt). Dort
www.access-basics.de
Bild 2: Das Formular frmZipper für die Verwaltung von Zip-Archiven
Seite 6
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
erzeugen Sie über das FileDialogObjekt von Office. Der hinter der
Schaltfläche liegende Code steht in
Listing 2. Falls Sie nicht den Abbrechen-Button betätigen, wird der
gewählte Dateiname in das Textfeld
txtZip übertragen.
Darunter befindet sich ein Listenfeld,
welches die dem Zip-Archiv hinzuzufügenden Dateien oder Ordner
aufnimmt. Diese öffnen Sie über die
beiden Schaltflächen rechts. Der
mit D... bezeichnete Button lässt die
Auswahl von Dateien zu, der mit O...
beschriftete öffnet einen Ordner-auswahldialog (siehe Bild 4). Während
für die Dateiauswahl wieder der Office-FileDialog in ähnlicher Form wie
im Listing zum Einsatz kommt, wird
zur Ordnerauswahl eine Methode
BrowseForFolder des Shell-Objekts
verwendet – denn die Office-Bibliothek kennt keinen solchen Auswahldialog. Wenn Sie eventuell den häufig
benutzten und umfangreichen APICode zum Anzeigen dieses Dialogs
kennen, werden Sie sich vielleicht
über den überschaubaren Code in
Listing 3 freuen. Der BrowseForFolder-Methode des Shell-Objekts
übergibt man ein Fenster-Handle
oder 0, den Titel des Dialogs, eine
Bild 3: Die Datei speichern-Oberfläche des Office-FileDialog-Objekts
Private Sub cmdSelect_Click()
Dim oDlg As Office.FileDialog
Set oDlg = Application.FileDialog(msoFileDialogSaveAs)
With oDlg
.Title = "Dateiname für ZIP-Archiv"
.InitialView = msoFileDialogViewDetails
.AllowMultiSelect = False
.InitialFileName = CurrentProject.Path & "\AB_Test.zip"
If .Show Then
Me!txtZip = .SelectedItems(1)
End If
End With
End Sub
Listing 2: Routine zum Anzeigen des Speichern unter-Dialogs von Office
Konstante, die das Erscheinungsbild
bestimmt, und schließlich ein Folder-
Objekt, das die oberste Ebene für
den Verzeichnisbaum einstellt. Hier
Function BrowseFolder() As String
Dim objShell As New Shell32.Shell
Dim objRootFolder As Shell32.Folder
Dim objFolder As Shell32.Folder
Set objRootFolder = objShell.NameSpace("Desktop")
Set objFolder = objShell.BrowseForFolder(hWndAccessApp, _
"Dateiname für ZIP-Archiv:", &H40, objRootFolder)
If objFolder Is Nothing Then Exit Function
BrowseFolder = objFolder.Self.Path
End Function
Bild 4: Shell-Verzeichnisauswahldialog
www.access-basics.de
Listing 3: Routine zur Anzeige des Ordnerauswahldialogs über das Shell-Objekt
Seite 7
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
wird der Desktop angegeben, während in der Abbildung als Root der
Computer steht, was durch Angabe
des Werts 17, statt "Desktop", für
den Shell-NameSpace gelingt.
Wenn Sie eine Übersicht über die
Zahlenwerte haben möchten, die für
den NameSpace möglich sind, so
rufen Sie die Prozedur EnumNameSpaces im Modul mdlZipShell aus
dem VBA-Direktfenster heraus auf.
Sie gibt alle Werte aus, die auf Ihrem
System angegeben werden können,
sowie die Bezeichnung und den
Pfad des Ordners, die, wie bereits
erwähnt, auch virtueller Natur sein
können, was an GUIDs für den Pfad
deutlich wird.
Bis hierhin wurden nur benötigte
Informationen für die Erstellung der
Zip-Datei gesammelt. Ein Klick auf
Zip-Archiv erzeugen im Formular
erst stößt die Prozeduren CreateZip
oder CreateZipFromFolder an, je
nachdem, ob im Listenfeld ein
Ordnerpfad steht, oder eine
Liste von Dateien. Im letzteren
Fall durchläuft die Prozedur
cmdCreateZip_Click alle
Einträge des Listenfelds und
speichert sie in einem StringArray, welches anschließend
der CreateZip-Routine übergeben wird.
Mit dieser hat es eine Besonderheit auf sich. Sie erstellt
nicht grundsätzlich eine
Zip-Datei neu, sondern nur
dann, wenn für den Parameter
Overwrite ein True angegeben wird. Ansonsten nutzt Sie
ein eventuell bereits vorhan-
www.access-basics.de
denes Archiv gleichen Namens im
Zielverzeichnis. Das bedeutet, dass
Sie über diese Routine einem Archiv
auch weitere Dateien hinzufügen
können. Und weiterhin, dass es
somit auch zu Kollisionen kommen
kann, wenn im Archiv schon eine
gleichnamige Datei existiert. Um
diesen Konflikt brauchen Sie sich indessen nicht zu kümmern. Die Shell
erkennt das selbst und konfrontiert
Sie mit dem Dialog aus Bild 5, in dem
Sie aufgefordert werden zu entscheiden, wie weiter verfahren werden
soll. Das Auftauchen des Dialogs
können Sie übrigens über keinen
Optionsparameter der CopyHereMethode unterbinden.
Das Formular stellt für CreateZip
und Overwrite allerdings True ein,
wodurch ein eventuell existierendes
Archiv ohne Nachfrage gelöscht und
neu erstellt wird. Demnach kann es
auch nicht zur Anzeige des Konfliktdialogs kommen. Denn dieser hat
einen Pferdefuß: Obwohl er noch
angezeigt wird, hält die Shell den
CopyHere-Vorgang nicht an und VBA
fährt asynchron mit der Ausführung
des Codes fort. So könnte es dazu
kommen, dass die Routine bereits
fertig und das Archiv damit angelegt ist, obwohl die Entscheidung
über das Ersetzen noch gar nicht
gefallen ist. Zwar modifiziert der
Shell-Prozess das Archiv dann noch
nachträglich, aber eine Kontrolle des
Vorgangs über VBA ist nicht möglich.
Nach dem Erzeugen der Zip-Datei
öffnet das Formular diese noch zur
Kontrolle über die ShellExecuteMethode des Shell-Objekts. Was hier
passiert hängt von Ihrem System ab.
Die Methode tut das Gleiche, wie ein
Doppelklick auf die Datei im Explorer.
Haben Sie etwa WinRar oder 7-Zip
installiert, so werden diese wohl mit
der Aufgabe des Öffnens betraut.
Wenn Sie die Module der Beispieldatenbank in eigene Anwendungen
einbauen möchten, so können
Sie selbstverständlich die
Zeilen mit dem ShellExecute
auch auskommentieren.
Bild 5: Das Shell-Objekt fragt vor dem Überschreiben
einer Datei im Zip-Archiv sicherheitshalber nach
Ist das Archiv erstellt, so ändert sich der Inhalt der Textfelder im Formular wie in Bild 6.
In die unteren beiden ist nun
gleich der Name der erstellten
Zip-Datei eingetragen und
zusätzlich noch ein Ordner angegeben, in den Sie die Datei
sogleich wieder entpacken
könnten. Dabei handelt sich
um den Ordner, in dem sich
auch die Zip-Datei befindet.
Ein Klick auf Zip-Archiv entpacken extrahiert die Dateien
Seite 8
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
Bild 6: Das Formular frmZipper nach dem Erstellen der Archivdatei
im Archiv dann in dieses Verzeichnis.
Natürlich kann es auch dabei wieder zur Anzeige des Konfliktdialogs
kommen.
Der der Schaltfläche hinterlegte
Code ruft lediglich die schon angesprochene Prozedur UnzipFile auf.
Nach dem Entpacken wird allerdings
zur Kontrolle noch der Zielordner
im Explorer geöffnet. Das lässt sich
abermals mit einer unscheinbaren
Methode Explore des Shell-Objekts
erledigen. Ihr übergibt man einfach
als String den Verzeichnispfad:
objShell.Explore CStr(Me!txtOutDir)
Die ausdrückliche Konvertierung
des Textfeldinhalts in einen OLEkonformen String über CStr ist übrigens notwendig. Ohne diese kann
die Shell mit dem Ausdruck nichts
anfangen.
www.access-basics.de
Vielleicht fällt Ihnen bei der Durchsicht der beiden Routinen zum Zippen noch auf, dass diese am Ende
die Hilfsfunktion WaitForFileReady
aufrufen. Mit ihr soll sichergestellt
werden, dass sich die Routinen erst
dann beenden, wenn das Archiv
wirklich fertiggestellt ist. Da ja CopyHere asynchron arbeitet, kann etwa
ein Archivierprogramm die Zip-Datei
noch nicht öffnen, solange die Shell
es im Zugriff hat. In Listing 4 finden
Sie diese Hilfsfunktion dargestellt.
Ihr Kern ist die Zeile für den Zugriff
auf die Datei per Open-Anweisung.
Diese ist mit den Parametern Access Read Write Lock Read Write
ausgestattet. Solange die Shell die
Datei noch bearbeitet, wird dieser
Zugriffsmodus wegen Dateisperrung
fehlschlagen, was durch die Fehlerbehandlung abgefangen wird. Die
Do-Loop-Schleife wird erst dann
verlassen, wenn dieser Fehler nicht
mehr auftritt. Damit die Schleife unter
Umständen nicht endlos durchläuft,
ist zusätzlich eine Timer-Funktion
eingebaut, die sie nach 30 Sekunden
(wählbar) auf jeden Fall unterbricht.
Bliebe noch die Schaltfläche mit
der Aufschrift Zip erzeugen und in
Anlage speichern des Formulars. Im
Prinzip löst diese nichts anderes aus,
als die darüber liegende. Die ZipDatei wird auf gleiche Weise erstellt.
Nur wird diese anschließend als Anlagedatensatz in die Tabelle MSys-
Function WaitForFileReady(ByVal FileName As String, Optional TimeOut As Single = 30)
Dim F As Integer
Dim T As Single
Dim bOK As Boolean
F = FreeFile
T = VBA.Timer
On Error Resume Next
Do
Sleep 50
DoEvents
Err.Clear
Open FileName For Binary Access Read Write Lock Read Write As F
If Err.Number = 0 Then bOK = True
Close F
Loop Until ((VBA.Timer - T) >= TimeOut) Or bOK
WaitForFileReady = (VBA.Timer - T) < TimeOut
End Function
Listing 4: Diese Funktion wird erst beendet, wenn die übergebene Datei frei ist
Seite 9
ACCESS
LÖSUNGEN
ZIPPEN MIT BORDMITTELN
BASICS
Resources aufgenommen, wenn Sie
mindestens Access 2010 verwenden,
und wieder gelöscht. Diese Systemtabelle ist in jeder unter Access 2010
ff. erstellten Datenbank mit am Start
und an sich für die Aufnahme von
Bildern für Formulare gedacht. Da sie
nicht schreibgeschützt ist, lässt sie
sich genauso gut für andere Zwecke
missbrauchen.
bringen, kann nun mit dem Rüstzeug
dieses Beitrags realisiert werden.
Der Code für das Speichern der ZipDatei im Anlagefeld über DAO soll
hier nicht weiter interessieren. Sie
finden ähnlichen Code auch an anderer Stelle. Statt der MSysResources können Sie natürlich auch eine
eigene Tabelle mit einem Anlagefeld
verwenden. Ändern Sie dann die
Routine cmdZipAttachment_Click
entsprechend ab.
In der Sicherungsroutine werden die
gefragten Datenbankobjekte als Textdateien exportiert, aber deren Dateinamen zusätzlich in ein String-Array
arrFiles aufgenommen. Das ist der
einzige Unterschied. Das Array wird
am Schluss für die schon bekannte
Prozedur CreateZip benötigt, die aus
den Dateien ein Archiv braut. Ist dieses erstellt, werden die Textdateien
in einer Schleife per Kill-Anweisung
wieder gelöscht.
Datensicherung zippen
In der letzten Ausgabe 01/2015 von
Access [basics] ging es im Beitrag
Datenbanken und Objekte sichern
unter anderem darum, die einzelnen
Objekte einer Datenbank, also Formulare, Berichte, Module, et cetera,
über die versteckte Access-Methode
SaveAsText in einzelne Textdateien
zu sichern, aus denen sie sich später
wiederherstellen lassen. Bei umfangreichen Datenbanken haben Sie
dann nach Durchlaufen der
Sicherungsroutine einen
Haufen Textdateien erzeugt. Die dort angestellte
Überlegung, diese Dateien
stattdessen platzsparend
in einem Zip-Archiv unter-
Das Modul mdlSaveObjects ist in
dieser Beispieldatenbank fast identisch zu der des erwähnten Beitrags.
Nur heißt die Routine zum Sichern
der Objekte hier ObjektSicherungZip, die zum Einlesen SicherungWiederherstellenZip.
Beim Test der Routine kam es allerdings zu Fehlern. Ein oder mehrere
der Fehlerdialoge aus Bild 7 poppten
auf. Das sind Meldungen der Shell
auf die Anweisung CopyHere hin,
die von VBA leider nicht abgefangen
werden können. Wieder einmal ist
das der asynchronen Verarbeitung
geschuldet. Das Verhalten konnte
erst korrigiert werden, nachdem in
die Schleife zum Hinzufügen von
Dateien zum Archiv in der Funktion
CreateZip eine Verzögerung von 100
ms mit der API-Anweisung Sleep
eingebaut wurde. Es hängt von der
Performance Ihres Systems ab, ob
Sie diese Zeile benötigen und wie
groß die Verzögerung sein muss, damit die Fehlermeldungen nicht mehr
auftreten.
Umgekehrt geht die Wiederherstellen-Routine vor. Zunächst entpackt
sie das als Parameter übergebene
Sicherungsarchiv ZipFile mit UnzipFile in ein neu angelegtes temporäres Verzeichnis \temp unterhalb des
Anwendungsverzeichnisses. Aus
dem Archiv werden dann die einzelnen Textdateien mit LoadFromText
gegebenenfalls wieder in Datenbankobjekte umgewandelt, wobei die
Routine für jedes einzelne Objekt
gesondert nachfragt. Ob wiederhergestellt, oder nicht, die Textdatei wird
im Anschluss sogleich gelöscht. Am
Ende der Schleife ist das temporäre
Verzeichnis damit leer und kann mit
der RmDir-Anweisung selbst gelöscht werden – sie funktioniert nur,
wenn das angegebene Verzeichnis
keinen Inhalt hat.
Gegenüber der ursprünglichen Version hat sich dieses Sicherungsmodul nur um wenige
Zeilen vergrößert, da hauptsächlich die Zip-Funktionen
des Moduls mdlZipShell
angesprochen werden.
Bild 7: Fehlermeldung der Shell beim Hinzufügen von Dateien und dabei verzögerter Aktualisierung des Zip-Archivs
www.access-basics.de
Seite 10