|  | Unser Angebot für Sie! Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'! |
| | | | | |
Dateien in Tabellen speichern
André Minhorst, Duisburg
"Dateien in einer Datenbank speichern - wer macht den so was? Schon mit ein paar kleinen Bildchen bläht man sich doch die Datenbank schon maßlos auf!" - so ähnlich ist die Meinung der meisten Access-Anwender zum Thema dieses Beitrags. Dass es auch ohne Aufblähen geht und dass auch das Speichern anderer Dateien als Bilddateien in der Datenbank sinnvoll sein kann, erfahren Sie nachfolgend - und natürlich lernen Sie auch Funktionen kennen, die Ihnen dabei eine Menge Arbeit abnehmen.
Warum Dateien in Tabellen speichern?
Wenn man nicht gerade zu den Leuten gehört, die gerade einen aktuellen Anwendungsfall zum Speichern von Dateien in einer Access-Datenbank haben, fragen Sie sich vielleicht, welche Gründe es überhaupt für das Speichern von Dateien in einer Tabelle gibt.
Dafür gibt es genügend Anwendungsbeispiele; die bekanntesten davon beschäftigen sich vermutlich mit der Verwaltung von Bildern. In den gängigen Foren fragen Besucher ständig nach Möglichkeiten, um Bilder in Access zu speichern - und das möglichst ohne dass die Datenbank schneller als gewünscht eine Größe von zwei Gigabyte erreicht.
Aber es gibt noch andere gute Gründe für das Speichern von Dateien in einer Datenbank. Wenn Sie beispielsweise eine Datenbank weitergeben, ohne direkt eine aufwändige Installationsroutine mitzuliefern, können Sie eventuell zusätzlich benötigte Anwendungen beim Start der Datenbankanwendung ins Datenbankverzeichnis kopieren und dort verwenden.
Und wenn der Autor hier einmal aus dem Nähkästchen plaudern darf: Er verwendet die weiter unten vorstellten Funktionen, um alle im Online-Archiv enthaltenen .pdf- und Beispieldateien in einer Datenbank zu verwalten und diese bei Bedarf inklusive entsprechender Verzeichnisstrukturen (Jahrgang/Ausgabe/Beitrag ...) auf der Festplatte zu speichern und entsprechend weiterzubearbeiten.
Ebenso leicht ist etwa die Verwendung eines kommandozeilengesteuerten Zip-Tools, um beliebige Dateien ins Filesystem zu kopieren, zu komprimieren und die Originaldateien anschließend wieder zu löschen.
Vorbereitungen
Um die Vorgehensweise in den folgenden Kapiteln nachvollziehen zu können, benötigen Sie eine Access-Datenbank mit einer Tabelle zum Speichern von Daten. Den Entwurf dieser Tabelle können Sie Abb. 1 entnehmen.

Abb. 1: Entwurf der Tabelle zum Speichern von Dateien
Public Function DateiInOLEFeld(strTabelle As String, strPrimaerschluessel As String, _ strZielfeld As String, lngID As Long, Optional strFeldSpeicherort As String, _ Optional strSpeicherort As String, Optional bolImDatenbankpfad As Boolean) As Long
Dim cnn As ADODB.Connection
Dim rst As New ADODB.Recordset
Dim strSpeicherortTemp As String, strSpeicherortName As String
Dim lngExportdateiID As Long
Dim Buffer() As Byte
Dim lngDateigroesse As Long
On Error GoTo DateiInOLEFeld_Err
Set cnn = CurrentProject.Connection
If Not strFeldSpeicherort = "" Then
strSpeicherortTemp = ", " & strFeldSpeicherort
Else
strSpeicherortTemp = ""
End If
rst.Open "SELECT " & strZielfeld & strSpeicherortTemp & " FROM " & strTabelle _ & " WHERE " & strPrimaerschluessel & " = " & lngID, cnn, adOpenDynamic, _ adLockOptimistic
lngExportdateiID = FreeFile
If Not strFeldSpeicherort = "" Then
strSpeicherortName = rst(strFeldSpeicherort)
Else
strSpeicherortName = strSpeicherort
End If
If bolImDatenbankpfad = True Then
strSpeicherortName = Datenbankpfad & strSpeicherortName
End If
If Dir(strSpeicherortName) = "" Then
MsgBox "Die Datei '" & strSpeicherortName & "' existiert nicht."
Exit Function
End If
Open strSpeicherortName For Binary Access Read Lock Read Write As lngExportdateiID
lngDateigroesse = FileLen(strSpeicherortName)
ReDim Buffer(lngDateigroesse)
rst(strZielfeld) = Null
Get lngExportdateiID, , Buffer
rst(strZielfeld).AppendChunk Buffer
rst.Update
Close lngExportdateiID
DateiInOLEFeld = True
DateiInOLEFeld_Exit:
rst.Close : Set rst = Nothing : Set cnn = Nothing
Exit Function
DateiInOLEFeld_Err:
DateiInOLEFeld = Err.Number
Resume DateiInOLEFeld_Exit
End Function
Quellcode 1
Dateien in einer Tabelle speichern
Die Prozedur zum Speichern einer Datei in einem Feld einer Tabelle finden Sie in Quellcode 1. Der Code sieht relativ umfangreich aus, aber die Prozedur gleicht dies durch hohe Flexibilität aus.
Eingabeparameter der Prozedur
Schauen Sie sich zunächst die Eingabeparameter an:
strTabelle: Tabelle, in der die Datei gespeichert werden soll
strPrimaerschluessel: Name des Primärschlüsselfeldes in der Zieltabelle
strZielfeld: OLE-Feld, in dem die Datei gespeichert werden soll
lngID: ID des Datensatzes, dem die Datei hinzugefügt werden soll
strFeldSpeicherort: Optional für die Angabe des Namens eines Feldes mit dem Speicherort der zu importierenden Datei
strSpeicherort: Optional für die Angabe des Speicherorts der zu importierenden Datei
bolImDatenbankpfad: Gibt an, ob dem Speicherort das Verzeichnis, in dem sich die Datenbank befindet, vorangestellt werden soll
Beispielaufrufe der Prozedur
Um nun beispielsweise eine Datei namens c:\test.pdf im Feld Datei der Beispieltabelle zu speichern, legen Sie zunächst einen neuen Datensatz in dieser Tabelle an (s. Abb. 2). Das Vorhandensein eines Datensatzes mit einem OLE-Feld ist Voraussetzung für den Einsatz dieser Prozedur.
Rufen Sie die Funktion im Testfenster nun folgendermaßen auf:

Abb. 2: Ein Datensatz vor dem Import einer Datei
DateiInOLEFeld "tblDateien", "DateiID", "Datei", 1, ,"c:\test.pdf",False
Dieser Aufruf speichert die Datei c:\test.pdf in der Tabelle tblDatei im Feld Datei des Datensatzes mit dem Wert 1 im Primärschlüsselfeld DateiID.
Nun können Sie mit dem .pdf-Dokument im OLE-Feld nicht allzu viel anfangen. Dass es aber dort angekommen ist, zeigt das erneute Öffnen der Tabelle (s. Abb. 3).

Abb. 3: Das OLE-Feld ist nicht mehr leer.
Eine zweite Variante für den Aufruf verwendet den Inhalt des Feldes Dateiname als Pfad für die zu importierende Datei:
DateiInOLEFeld "tblDateien", "DateiID", "Datei", 1, "Speicherort", , False
Durch die Angabe des Wertes "Speicherort" für den Parameter strFeldSpeicherort importiert die Funktion die in diesem Feld angegebene Datei - falls Sie die Datei aus dem vorherigen Beispiel nicht gelöscht haben, wird diese einfach überschrieben.
Diese beiden Varianten können beide mit der Möglichkeit, den aktuellen Datenbankpfad einzubauen, kombiniert werden.
Wenn Sie den Dateinamen im Funktionsaufruf übergeben möchten, verwenden Sie den reinen Dateinamen ohne Pfadangabe und übergeben für den Parameter bolImDatenbankpfad den Wert True. Das Gleiche gilt, wenn Sie den in der Tabelle gespeicherten Dateinamen verwenden möchten - geben Sie einfach den puren Dateinamen an und verwenden Sie die obige Option.
Aufbau der Prozedur
Die Prozedur besteht zu einem Großteil aus If Then-Bedingungen, die einen den Parametern entsprechenden Dateinamen ermitteln. Außerdem wird im ersten Teil der Prozedur ein Recordset mit dem angegebenen Datensatz der Zieltabelle geöffnet. Erst mit der Open-Anweisung wird die Prozedur richtig interessant und führt folgende Aktionen durch:
Öffnen der einzulesenden Datei
Ermitteln der Dateigröße
Anpassen der Größe der Byte-Variablen Buffer
Schreiben der Datei als Binärdaten in die Variable Buffer
Einfügen des Inhalts dieser Variablen in das Feld Datei des Ziel-Recordsets
Aktualisieren und damit Speichern des bearbeiteten Datensatzes
Dateien aus einer Tabelle ins Filesystem exportieren
Erst mit der Möglichkeit, die Dateien wieder ins Filesystem zu speichern, wird die im vorherigen Kapitel vorgestellte Prozedur interessant.
Die entsprechende Funktion heißt OLEFeldInDatei und ist in Quellcode 2 zu finden. Die Eingabeparameter stimmen weitgehend mit denen der Funktion DateiInOLEFeld überein, wenn auch für die umgekehrte Richtung.
Voraussetzung für den Export des Inhalts eines OLE-Feldes in eine Datei ist eine Tabelle mit einem OLE-Feld, das mindestens einen Datensatz mit einem gefüllten OLE-Feld enthält.
Die folgenden Beispiele verdeutlichen die Anwendung dieser Funktion. Mit dem ersten Aufruf speichern Sie die soeben importierte Datei im gleichen Verzeichnis, aber unter einem anderen Dateinamen:
OLEFeldInDAtei "tblDateien", "DateiID", "Datei", 1, ,"c:\ExportTest.pdf"
Nun stellen Sie die Funktion beider Prozeduren gleichzeitig auf die Probe: Wenn sich das .pdf-Dokument öffnen lässt und mit dem ursprünglichen Dokument übereinstimmt, sind die Funktionen einsatzbereit. Und da der Autor mit diesen beiden Funktionen schon einige Dateien in einer Datenbank gespeichert und auch wieder dort hervorgeholt hat, sollte das nun auch bei Ihnen funktionieren.
Im zweiten Beispiel soll die .pdf-Datei unter dem Namen ExportTest.pdf im aktuellen Datenbankverzeichnis gespeichert werden:
OLEFeldInDAtei "tblDateien", "DateiID", "Datei", 1, ,"c:\ExportTest.pdf",True
Auch dieser Aufruf tut seinen Dienst einwandfrei. Werfen Sie nun einen Blick auf den Quellcode: Wie bei der vorherigen Funktion ermittelt auch hier der erste Teil der Prozedur den zu verwendenden Dateinamen aus den übergebenen Parametern und öffnet den Datensatz, in dem die zu exportierende Datei enthalten ist.
Der Rest ist eine genaue Umkehrung der Funktion DateiInOLEFeld: Die Prozedur ermittelt die Dateigröße, schreibt den Inhalt des Feldes in die entsprechend dimensionierte Buffer-Variable und bugsiert deren Inhalt in eine zuvor angelegte Datei.
Beispielanwendung: Bilder
Die erste Beispielanwendung für diese beiden Funktionen ist die Verwaltung von Bildern, ohne die Datenbank aufzublähen. Das passiert nämlich, wenn Bilder mit Access-Hausmitteln in ein OLE-Feld importiert werden. Access speichert die Bilder dann im Windows-eigenen Format, was entsprechend mehr Speicher frisst.
Public Function OLEFeldInDatei(strTabelle As String, strPrimaerschluessel As String, _ strQuellfeld As String, lngID As Long, Optional strFeldSpeicherort As String, _ Optional strSpeicherort As String, Optional bolImDatenbankpfad As Boolean) As Long
Dim cnn As ADODB.Connection
Dim rst As New ADODB.Recordset
Dim strSpeicherortTemp As String
Dim strSpeicherortName As String
On Error GoTo OLEFeldInDatei_Err
Set cnn = CurrentProject.Connection
If Not strFeldSpeicherort = "" Then
strSpeicherortTemp = ", " & strFeldSpeicherort
Else
strSpeicherortTemp = ""
End If
rst.Open "SELECT " & strQuellfeld & strSpeicherortTemp & " FROM " & strTabelle _ & " WHERE " & strPrimaerschluessel & " = " & lngID, cnn, adOpenDynamic, _ adLockOptimistic
Dim lngExportdateiID As Long
Dim Buffer() As Byte
Dim lngDateigroesse As Long
lngExportdateiID = FreeFile
If Not strFeldSpeicherort = "" Then
strSpeicherortName = rst(strFeldSpeicherort)
Else
strSpeicherortName = strSpeicherort
End If
If bolImDatenbankpfad = True Then
strSpeicherortName = Datenbankpfad & strSpeicherortName
End If
lngDateigroesse = Nz(LenB(rst(strQuellfeld)), 0)
If lngDateigroesse > 0 Then
ReDim Buffer(lngDateigroesse)
Open strSpeicherortName For Binary Access Write As lngExportdateiID
Buffer = rst(strQuellfeld).GetChunk(lngDateigroesse)
Put lngExportdateiID, , Buffer
Close lngExportdateiID
End If
OLEFeldInDatei = True
OLEFeldInDatei_Exit:
rst.Close
Set rst = Nothing
Set cnn = Nothing
Exit Function
OLEFeldInDatei_Err:
OLEFeldInDatei = Err.Number
Resume OLEFeldInDatei_Exit
End Function
Quellcode 2
Mit der hier vorgestellten Methode speichern Sie die Bilder in Originaldateigröße, können diese aber nicht direkt in einem OLE-Steuerelement anzeigen lassen.
Private Sub Form_Current()
Dim strDateiname As String
Dim strDatenbankpfad As String
If Not Me.NewRecord Then
strDateiname = DLookup("Dateiname", "tblDateien", "DateiID = " & Me.DateiID)
strDateiname = DateinameOhnePfad(strDateiname)
strDatenbankpfad = Datenbankpfad
OLEFeldInDatei "tblDateien", "DateiID", "Datei", Me.DateiID, , strDateiname, _ True
If Dir(strDatenbankpfad & strDateiname) = "" Then
Me.objPicture.Picture = ""
Else
Me.objPicture.Picture = strDatenbankpfad & strDateiname
End If
Else
Me.objPicture.Picture = ""
End If
End Sub
Quellcode 3
Dazu sind dann der vorherige Export und das Einstellen der Herkunftsdatei im OLE-Steuerelement erforderlich.
|