{"id":55001118,"date":"2018-02-01T00:00:00","date_gmt":"2020-05-13T21:18:17","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1118"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Datenkompression_leicht_gemacht","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/","title":{"rendered":"Datenkompression leicht gemacht"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Wenn Sie l&auml;ngere Texte in Tabellen abspeichern oder umfangreiche Bin&auml;rdaten in OLE-Feldern ablegen, so bl&auml;ht das die Datenbank auf. W&auml;hrend dieser Umstand bei lokalen Datenbanken heutzutage kein Problem mehr darstellt, sieht die Sache in einer Mehrbenutzerumgebung und Netzwerkzugriffen auf Backends schon anders aus. Hier sollte der Traffic minimiert werden. Da macht sich dann die Komprimierung solcher Datenfelder gut, was zu verbesserter Performance f&uuml;hren kann.<\/b><\/p>\n<h2>Komprimieren von Memo- und Long-Binary-Feldern<\/h2>\n<p>&uuml;ber das F&uuml;r und Wider von in Tabellen abgelegten Bin&auml;rdaten oder Textdokumente m&ouml;chten wir hier nicht diskutieren. Das kann ganz einfach immer wieder vorkommen, und es gibt ganze Serverumgebungen, die davon weidlich Gebrauch machen, wie etwa der <b>Microsoft Sharepoint-Server<\/b>. Die Kompression dieser Daten verkleinert die Datenbankdateien und hilft dabei den ben&ouml;tigten Traffic zu den Clients zu verringern. <\/p>\n<p>An sich ist derlei bereits in Access integriert. Der Datentyp <b>Anlage<\/b> (<b>Attachment<\/b>) speichert bin&auml;re Daten und komprimiert diese nach Bedarf, wobei Microsoft sich weitgehend dar&uuml;ber ausschweigt, bei welchen Dateitypen dies zutrifft und welcher Kompressionsalgorithmus zum Einsatz kommt. Nicht jeder ist jedoch ein Freund von <b>Anlage-Feldern<\/b>, denn aufgrund des dahinter liegenden versteckten Datenmodells, welches sich tats&auml;chlich von <b>Sharepoint<\/b>-Technik ableitet, ist der programmtechnische Umgang mit ihnen recht komplex. Zudem k&ouml;nnen Anlagefelder nicht in <b>Access 2003<\/b> oder fr&uuml;her angezeigt oder ausgelesen werden. Deshalb macht sich die Bin&auml;rspeicherung in <b>OLE-Feldern<\/b>, bei denen es sich ja schlicht um <b>Long-Binary<\/b>-Felder handelt, besser.<\/p>\n<p>Das Thema ist nicht neu. Bereits in der Ausgabe <b>3\/2007<\/b> (<b>Shortlink 466<\/b>) von <b>Access Im Unternehmen<\/b> wurde es behandelt, weshalb wir an dieser Stelle zus&auml;tzlich auf jenen Beitrag verweisen. Dort wurde die Komprimierung &uuml;ber eine externe Komponente erreicht, eine <b>zlib-DLL<\/b>, auf die im VBA-Projekt verwiesen wird. Darauf kann verzichtet werden, wenn man sich der wenig beachteten Windows-API-Funktion <b>RTLCompressBuffer<\/b> bedient, die eigentlich zur Abteilung der Treiber-APIs geh&ouml;rt. Sie erreicht, vor allem bei Texten, durchaus vergleichbare Kompressionsraten. Der eingesetzte Algorithmus ist eine <b>LZ<\/b>-Variante (<b>Lempel-Ziv<\/b>).<\/p>\n<h2>Einschub: Kompression in Anlagefeldern<\/h2>\n<p>Da Microsoft keine komplette Liste ver&ouml;ffentlicht, welche Dateitypen in <b>Anlage-Feldern<\/b> denn nun komprimiert werden und welche nicht, sondern pauschal behauptet, dass jene unbearbeitet blieben, die bereits hinl&auml;nglich komprimiert sind, wie etwa <b>JPG<\/b>, haben wir einen einfachen Test unternommen. Eine Datenbank enth&auml;lt eine Tabelle, die wiederum nur ein <b>Anlage-Feld<\/b> enth&auml;lt. Wir messen die Dateigr&ouml;&szlig;e dieser <b>ACCDB<\/b> nach dem Hinzuf&uuml;gen jeweils <b>einer<\/b> gr&ouml;&szlig;eren Datei eines bestimmten Typs und anschlie&szlig;endem <b>Komprimieren und Reparieren<\/b> der Datenbank. Verwendet werden g&auml;ngige Dateitypen. Steigt die Gr&ouml;&szlig;e der <b>ACCDB<\/b> um die Gr&ouml;&szlig;e der hinzugef&uuml;gten Datei, so d&uuml;rfte die interne Kompression der <b>Anlage<\/b> nicht angesprochen haben. Die folgende Tabelle gibt Auskunft &uuml;ber das Ergebnis:<\/p>\n<pre>&lt;b&gt;Dateityp&nbsp;&nbsp;&nbsp;&nbsp;Gr&ouml;&szlig;e Datei&nbsp;&nbsp;&nbsp;&nbsp;Gr&ouml;&szlig;e DB&nbsp;&nbsp;&nbsp;&nbsp;Kompression, ca.\r\n(leer)&nbsp;&nbsp;&nbsp;&nbsp;-&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;404 kB&nbsp;&nbsp;&nbsp;&nbsp;-\r\ntxt&nbsp;&nbsp;&nbsp;&nbsp;3770 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1020 kB&nbsp;&nbsp;&nbsp;&nbsp;6-fach\r\ndoc&nbsp;&nbsp;&nbsp;&nbsp;3430 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1778 kB&nbsp;&nbsp;&nbsp;&nbsp;2,5-fach\r\nrtf&nbsp;&nbsp;&nbsp;&nbsp;4400 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;524 kB&nbsp;&nbsp;&nbsp;&nbsp;37-fach\r\nxls&nbsp;&nbsp;&nbsp;&nbsp;3640 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1020 kB&nbsp;&nbsp;&nbsp;&nbsp;6-fach\r\nppt&nbsp;&nbsp;&nbsp;&nbsp;3800 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;676 kB&nbsp;&nbsp;&nbsp;&nbsp;14-fach\r\npdf&nbsp;&nbsp;&nbsp;&nbsp;3280 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2208 kB&nbsp;&nbsp;&nbsp;&nbsp;1,8-fach\r\nbmp&nbsp;&nbsp;&nbsp;&nbsp;4130 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;516 kB&nbsp;&nbsp;&nbsp;&nbsp;34-fach\r\njpg&nbsp;&nbsp;&nbsp;&nbsp;4300 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4752 kB&nbsp;&nbsp;&nbsp;&nbsp;keine\r\ntiff &nbsp;&nbsp;&nbsp;&nbsp;3050 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3305 kB&nbsp;&nbsp;&nbsp;&nbsp;keine\r\nxml&nbsp;&nbsp;&nbsp;&nbsp;3830 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;992 kB&nbsp;&nbsp;&nbsp;&nbsp;6,5-fach\r\nkml&nbsp;&nbsp;&nbsp;&nbsp;6650 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;540 kB&nbsp;&nbsp;&nbsp;&nbsp;49-fach\r\ncsv&nbsp;&nbsp;&nbsp;&nbsp;3380 kB&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;740 kB&nbsp;&nbsp;&nbsp;&nbsp;10-fach<\/pre>\n<p>Zu erw&auml;hnen w&auml;re noch, dass dezidiert Dateien verwendet wurden, die entweder viele Wiederholungen enthalten oder viele <b>Null-Bytes<\/b>, sich mithin also gut komprimieren lassen. Das Ergebnis ist eindeutig: Die Kompression scheint zum Gl&uuml;ck der Default zu sein. Nur ausgew&auml;hlte Dateiformate, wie J<b>PG, ZIP, DOCX, XLSX<\/b>, die bekannterweise schon eine Kompression aufweisen, werden ausgenommen. Erstaunlich hoch sind die Kompressionsraten. Dass etwa eine <b>RTF-Datei<\/b> von &uuml;ber <b>4 MB<\/b> Gr&ouml;&szlig;e auf intern <b>120 kB<\/b> schrumpft, war nicht zu erwarten. Als Datei-Container eignen sich <b>Anlage-Felder <\/b>demnach hervorragend. <\/p>\n<p>Leider kann der in diesem Beitrag vorgestellte Algorithmus da nicht mithalten. Dennoch hat er seine Existenzberechtigung, und wir f&uuml;hren kurz die Vorteile gegen&uuml;ber <b>Attachments<\/b> auf:<\/p>\n<ul>\n<li>Die komprimierte Speicherung ist nicht nur auf Dateien beschr&auml;nkt, sondern kann etwa auch auf beliebige per VBA generierte Strings angewandt werden.<\/li>\n<li>Die Speicherung in OLE-Feldern kann auch in Access 2003 und fr&uuml;her erfolgen.<\/li>\n<li>Auch EXE-Dateien k&ouml;nnen integriert werden, was Access bei Anlage-Feldern verbietet.<\/li>\n<li>OLE-Felder lassen sich &uuml;ber ODBC ansprechen und deren Inhalte sind damit auch f&uuml;r SQL-Server oder andere DBMS nicht tabu.<\/li>\n<li>Der Umgang mit Long-Binary-Feldern ist unter VBA und DAO, sowie ADODB, erheblich einfacher, als mit <b>Attachments<\/b>.<\/li>\n<\/ul>\n<h2>Kompressionsroutine<\/h2>\n<p>Das Modul <b>mdlCompression<\/b> der Beispieldatenbank enth&auml;lt eine Funktion <b>CompressRTL<\/b>, die <b>Byte-Arrays<\/b> komprimieren kann. Ihr Code ist in Listing 1 abgebildet. Er nutzt einige<b> Windows-API-Funktionen<\/b>, die im Modulkopf deklariert sind (Listing 2). Der R&uuml;ckgabewert ist wiederum ein <b>Byte-Array <\/b>mit den komprimierten Daten. Das Ganze kommt ausgesprochen &uuml;bersichtlich daher. Auf die genaue Funktion des Codes und der <b>API-Aufrufe<\/b> m&ouml;chten wir hier gar nicht eingehen. Einige Hinweise d&uuml;rfen jedoch nicht fehlen.<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>Declare Function RtlGetCompressionWorkSpaceSize _\r\n     Lib \"NTDLL\" (ByVal Flags<span style=\"color:blue;\"> As Integer<\/span>, WorkSpaceSize<span style=\"color:blue;\"> As <\/span>_\r\n     Long, UNKNOWN_PARAMETER<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>Declare Function NtAllocateVirtualMemory Lib _\r\n     \"ntdll.dll\" (ByVal ProcHandle<span style=\"color:blue;\"> As Long<\/span>, BaseAddress<span style=\"color:blue;\"> As <\/span>_\r\n     Long, ByVal NumBits<span style=\"color:blue;\"> As Long<\/span>, regionsize<span style=\"color:blue;\"> As Long<\/span>, ByVal _\r\n     Flags<span style=\"color:blue;\"> As Long<\/span>, ByVal ProtectMode<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>Declare Function RtlCompressBuffer Lib \"NTDLL\" _\r\n     (ByVal Flags<span style=\"color:blue;\"> As Integer<\/span>, ByVal BuffUnCompressed<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal UnCompSize<span style=\"color:blue;\"> As Long<\/span>, ByVal BuffCompressed<span style=\"color:blue;\"> As Long<\/span>, _\r\n     ByVal CompBuffSize<span style=\"color:blue;\"> As Long<\/span>, ByVal UNKNOWN_PARAMETER<span style=\"color:blue;\"> As <\/span>_\r\n     Long, OutputSize<span style=\"color:blue;\"> As Long<\/span>, ByVal WorkSpace<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As <\/span>_\r\n     Long\r\n<span style=\"color:blue;\">Private <\/span>Declare Function RtlDecompressBuffer Lib _\r\n     \"NTDLL\" (ByVal Flags<span style=\"color:blue;\"> As Integer<\/span>, ByVal BuffUnCompressed _\r\n    <span style=\"color:blue;\"> As Long<\/span>, ByVal UnCompSize<span style=\"color:blue;\"> As Long<\/span>, ByVal BuffCompressed _\r\n    <span style=\"color:blue;\"> As Long<\/span>, ByVal CompBuffSize<span style=\"color:blue;\"> As Long<\/span>, OutputSize<span style=\"color:blue;\"> As <\/span>_\r\n     Long)<span style=\"color:blue;\"> As Long<\/span>\r\n<span style=\"color:blue;\">Private <\/span>Declare Function NtFreeVirtualMemory Lib _\r\n     \"ntdll.dll\" (ByVal ProcHandle<span style=\"color:blue;\"> As Long<\/span>, BaseAddress<span style=\"color:blue;\"> As <\/span>_\r\n     Long, regionsize<span style=\"color:blue;\"> As Long<\/span>, ByVal Flags<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As Long<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Die f&uuml;nf im Modul verwendeten API-Funktionen<\/span><\/b><\/p>\n<p>So enth&auml;lt die Prozedur keine Fehlerbehandlung. &uuml;bergeben Sie etwa ein undimensioniertes Array, so kracht es gleich in der ersten Zeile beim Ausdruck <b>UBound<\/b>. Auch sonst werden die R&uuml;ckgabewerte der API-Funktionen nicht ausgewertet, so dass Fehlfunktionen nicht offensichtlich sind. Allerdings d&uuml;rfte es auch kaum einen Fall geben, der hier bei einem ordnungsgem&auml;&szlig;en Byte-Array zu Fehlern f&uuml;hrt. Kritisch ist bestenfalls der Wert der von <b>RTLCompressBuffer<\/b> zur&uuml;ckgelieferten Variablen <b>retSize<\/b>, die angibt, wie viele Bytes im Ergebnis enthalten sind. Er wird im weiteren Verlauf dazu verwendet, um das Ergebnis-Array <b>binOut<\/b> neu zu dimensionieren. Hier k&ouml;nnten rein theoretisch Werte anfallen, die &uuml;ber den erlaubten Wertebereich hinausgehen. Uns ist bei allen Tests derlei aber nicht untergekommen.<\/p>\n<p>Nun m&ouml;chten Sie m&ouml;glicherweise nicht Byte-Arrays komprimieren, sondern Strings. Das macht eine Konvertierung dieser erforderlich. Gegeben sei etwa ein Text in der Variablen <b>sText<\/b>, der zu komprimieren w&auml;re. Dann verwenden Sie die VBA-Funktion <b>StrConv<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>binRet()<span style=\"color:blue;\"> As Byte<\/span>\r\nbin = StrConv(sText, vbFromUnicode)\r\nbinRet = CompressRTL(bin)<\/pre>\n<p><b>StrConv<\/b> kann Strings in Byte-Arrays &uuml;berf&uuml;hren und umgekehrt. Da es sich bei VBA-Strings immer um <b>Unicode<\/b> handelt, ist der Parameter <b>vbFromUnicode<\/b> der richtige. Er macht aus dem String quasi ein <b>ANSI-Byte-Array<\/b>. Dieses &uuml;bergeben Sie dann der Funktion <b>CompressRTL<\/b> des Moduls.<\/p>\n<h2>Dekompressionsroutine<\/h2>\n<p>Mit dem komprimierten <b>Byte-Array<\/b> selbst k&ouml;nnen Sie wenig anfangen. Entweder speichern Sie es in einer Datei ab, oder im <b>OLE-Feld <\/b>einer Tabelle. Es reicht dazu schlicht die Zuweisung an den Feldinhalt. Beispiel:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rs<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n<span style=\"color:blue;\">Set<\/span> rs = CurrentDb.OpenRecordset(\"Binaertabelle\")\r\nrs.Edit&nbsp;&nbsp;&nbsp;&nbsp;''''oder rs.Add<span style=\"color:blue;\">New<\/span>\r\nrs!OleFeld1.Value = binRet\r\nrs.Update<\/pre>\n<p>Einstmals mussten Sie sich mit der Methode <b>AppendChunk<\/b> eines <b>DAO<\/b>-Felds herumschlagen und in einer Schleife Teile des Byte-Arrays (<b>Chunks<\/b>) hinzuf&uuml;gen. Das ist veraltet. Die unmittelbare Zuweisung funktioniert bei heutigen Rechnerausstattungen auch bei gro&szlig;en Byte-Arrays. Das Limit liegt lediglich beim dem <b>DAO-Thread<\/b> zugewiesenen RAM-Bereich (<b>Heap Working Set<\/b>) der Datenbank-Engine.<\/p>\n<p>Nun m&ouml;chten Sie die komprimierten Daten wieder in ihrer urspr&uuml;nglichen Form zur&uuml;ckgewinnen. Das &uuml;bernimmt die Dekompressionsroutine <b>DecompressRTL<\/b> des Moduls, welche in Listing 3 abgebildet ist. Auch ihr Umfang ist erfreulich gering. Ihr Aufruf entspricht genau dem f&uuml;r die Komprimierprozedur <b>CompressRTL<\/b>. Sie holen sich etwa die komprimierten Daten aus der Tabelle und erhalten die entpackten im R&uuml;ckgabe-Array, welches Sie wieder per <b>StrConv<\/b> in einen Text verwandeln:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>DeCompressRTL(Buffer()<span style=\"color:blue;\"> As Byte<\/span>)<span style=\"color:blue;\"> As Byte<\/span>()\r\n     <span style=\"color:blue;\">Dim <\/span>LSize<span style=\"color:blue;\"> As Long<\/span>, memSize<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>binOut()<span style=\"color:blue;\"> As Byte<\/span>\r\n     \r\n     LSize = <span style=\"color:blue;\">UBound<\/span>(Buffer) * 12.5\r\n     ReDim binOut(LSize)\r\n     RtlDecompressBuffer 2& Or &H100, VarPtr(binOut(0)), LSize, _\r\n         VarPtr(Buffer(0)), 1& + <span style=\"color:blue;\">UBound<\/span>(Buffer), memSize\r\n     If (memSize &gt; 0) And (memSize &lt;= <span style=\"color:blue;\">UBound<\/span>(binOut)) And _\r\n        (memSize &lt; 2000000) Then\r\n         ReDim Preserve binOut(memSize - 1)\r\n         DeCompressRTL = binOut\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><!--30percent--><\/p>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Routine DecompressRTL zum Entpacken der Byte-Arrays<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rs<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n<span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>binRet()<span style=\"color:blue;\"> As Byte<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>sText<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Set<\/span> rs = CurrentDb.OpenRecordset(\"Binaertabelle\")\r\nbin = rs!OleFeld1.Value\r\nbinRet = DecompressRTL(bin)\r\nsText = StrConv(binRet, vbUnicode)<\/pre>\n<p>Die String-Umwandlung passiert nun nat&uuml;rlich umgekehrt mittels des Parameters <b>vbUnicode<\/b>. Haben Sie nicht Texte, sondern Dateien komprimiert, so entf&auml;llt die Umwandlung per <b>StrConv<\/b> selbstverst&auml;ndlich jeweils.<\/p>\n<h2>Dateien komprimiert im OLE-Feld<\/h2>\n<p>Das bisher Gesagte zusammengefasst m&uuml;ndet in ein praktisches Beispiel, das so auch in der Demo-Datenbank vorhanden ist. Alle Dateien eines bestimmten Verzeichnisses sollen komprimiert als Datens&auml;tze in einer Tabelle abgespeichert werden. Die daf&uuml;r vorgesehene Routine <b>ImportFiles<\/b> finden Sie in Listing 4, die Entwurfsansicht der Zieltabelle in Bild 1.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/tblBinary_DS.png\" alt=\"Aufbau der Tabelle tblBinary zum Abspeichern bin&auml;rer Daten\" width=\"425\" height=\"234,2949\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Aufbau der Tabelle tblBinary zum Abspeichern bin&auml;rer Daten<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>ImportFiles(Byval sDir<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>sFile<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>rs<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>F<span style=\"color:blue;\"> As Integer<\/span>\r\n     \r\n     CurrentDb.Execute \"DELETE FROM tblBinary\"\r\n     <span style=\"color:blue;\">Set<\/span> rs = CurrentDb.OpenRecordset( _\r\n         \"SELECT * FROM tblBinary\", dbOpenDynaset)\r\n     sFile = Dir(sDir & \"\\*.*\")\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Len<\/span>(sFile) &gt; 0\r\n         F = FreeFile\r\n         Open sDir & \"\\\" & sFile For Binary<span style=\"color:blue;\"> As <\/span>F\r\n         ReDim bin(LOF(F) - 1)\r\n         Get F, , bin\r\n         Close F\r\n         \r\n         <span style=\"color:blue;\">With<\/span> rs\r\n             .Add<span style=\"color:blue;\">New<\/span>\r\n             !Path = sDir & \"\\\" & sFile\r\n             !File<span style=\"color:blue;\">Len<\/span> = File<span style=\"color:blue;\">Len<\/span>(sPath)\r\n             !BLOB.Value = bin\r\n             !CompressedBLOB.Value = CompressRTL(bin)\r\n             !LenCompressed = !CompressedBLOB.FieldSize\r\n             !Ratio = Round(!FileLen.Value \/ _\r\n                 !LenCompressed.Value, 3)\r\n             .Update\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         sFile = Dir\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     rs.Close\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Einlesen der Dateien eines Verzeichnisses in die Tabelle<\/span><\/b><\/p>\n<p>Das Feld <b>Path<\/b> nimmt den vollst&auml;ndigen Pfad zur Datei auf, <b>FileLen<\/b> deren Gr&ouml;&szlig;e in Bytes. <b>BLOB<\/b> ist der Container f&uuml;r die unkomprimierten Daten. In der Praxis w&uuml;rden Sie dieses Feld nicht verwenden, da im OLE-Feld <b>CompressedBLOB<\/b> die komprimierten Daten stehen, aus denen die Datei ja wiederhergestellt werden kann. <b>LenCompressed<\/b> speichert die Gr&ouml;&szlig;e der komprimierten Daten und <b>Ratio<\/b> als Gleitkommazahl das Kompressionsverh&auml;ltnis. Diese beiden letzten Felder k&ouml;nnte man ebenfalls weglassen, da sich <b>LenCompressed<\/b> aus <b>CompressedBLOB.FieldSize<\/b> erg&auml;be, und <b>Ratio<\/b> aus Selbigem geteilt durch <b>FileLen<\/b>. Die beiden Felder sind hier integriert, damit man in der Datenblattansicht der Tabelle gleich eine &uuml;bersicht &uuml;ber den Erfolg der Kompression hat.<\/p>\n<p>Die mit einigen Beispieldateien gef&uuml;llte Tabelle zeigt Bild 2. Sie ist absteigend nach dem Kompressionsfaktor (<b>Ratio<\/b>) sortiert. Es wird deutlich, dass sich bei den Bilddateien und PDFs keine nennenswerte Kompression einstellt. <b>Notepad.exe<\/b> verringert sich immerhin um ein Viertel. Bei den Bitmaps h&auml;ngt der Faktor vom Bildinhalt ab. Je mehr gleichfarbige Fl&auml;chen enthalten sind, desto besser die Kompression. Dasselbe gilt f&uuml;r Excel- und Word-Dokumente. Die Kompression ist umso erfolgreicher, je mehr Wortdoppelungen in diesen Dokumenten enthalten sind. <\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/tblBinary.png\" alt=\"Die Datenblattansicht der Tabelle tblBinary zeigt den Ursprung der Dateien neben zus&auml;tzlichen Angaben zur Kompression\" width=\"700\" height=\"258,8403\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Die Datenblattansicht der Tabelle tblBinary zeigt den Ursprung der Dateien neben zus&auml;tzlichen Angaben zur Kompression<\/span><\/b><\/p>\n<p>Wir haben alle Dateien zum Vergleich einmal in <b>ZIP-Archive<\/b> gepackt. Die resultierenden Dateigr&ouml;&szlig;en sind allgemein deutlich geringer, als die mit der API-Funktion erreichten. Das Nonplusultra stellt der Algorithmus von <b>RTLCompressBuffer<\/b> also nicht dar. Daf&uuml;r arbeitet die Funktion allerdings au&szlig;erordentlich schnell. M&ouml;chten Sie etwa eine gr&ouml;&szlig;ere Zahl von Office-Dokumenten in Ihrer Datenbank ablegen, so verkleinern Sie deren Dateigr&ouml;&szlig;e mit der Kompression etwa um den Faktor zwei bis drei.<\/p>\n<p>Doch zur&uuml;ck zur Prozedur in <b>Listing 4<\/b>. Hier werden in einer <b>Do While<\/b>-Schleife alle Dateien des als Parameter &uuml;bergebenen Verzeichnisses <b>sDir<\/b> abgearbeitet und in die Tabelle <b>tblBinary<\/b> &uuml;bertragen. Auf diese ist, nachdem sie in der ersten Zeile geleert wird, ein Recordset <b>rs<\/b> ge&ouml;ffnet. Eine Datei liest die <b>Open-Anweisung<\/b> im Bin&auml;rmodus in das Byte-Array <b>bin<\/b> ein. Dessen Inhalt wird direkt dem Feld <b>BLOB<\/b> als Wert &uuml;bergeben, w&auml;hrend das Feld <b>CompressedBLOB<\/b> das Ergebnis des Funktionsaufrufs der weiter oben behandelten Prozedur <b>CompressRTL<\/b> speichert. Das Einlesen der Dateien von Bild 2 dauerte bei uns mit dieser Routine gerade einmal eine Sekunde! Die Kompression selbst geschah jeweils in wenigen Millisekunden.<\/p>\n<h2>Texte komprimiert im OLE-Feld<\/h2>\n<p>F&uuml;r das Abspeichern komprimierter Textdateien gibt es in der Beispieldatenbank eine gesonderte Tabelle <b>tblTexte<\/b> (s. Bild 3) und eine eigene Prozedur <b>ImportTexts<\/b>. Diese Routine entspricht ziemlich genau der vorigen Prozedur <b>ImportFiles<\/b>, weshalb ein Listing entfallen kann. Nur benutzt sie zus&auml;tzlich die Konvertierung des eingelesenen Byte-Arrays per <b>StrConv<\/b> in Strings. Die wiederum nimmt das Memo-Feld <b>Text<\/b> auf, w&auml;hrend die komprimierten Daten in das OLE-Feld <b>CompressedText<\/b> gelangen. Der Aufbau der Tabelle entspricht ansonsten dem von <b>tblBinary<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/tblTexte_DS.png\" alt=\"Aufbau der Tabelle tblTexte zum Abspeichern langer Texte\" width=\"425\" height=\"247,5516\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Aufbau der Tabelle tblTexte zum Abspeichern langer Texte<\/span><\/b><\/p>\n<p>Als Dateitypen kommen hier nicht nur <b>TXT<\/b>-Dateien infrage, sondern etwa auch <b>CSV<\/b>&#8211; oder <b>XML<\/b>-Dateien. Das Ergebnis eines Tests von <b>ImportTexts<\/b> mit einigen Dateien zeigt Bild 4. Die Kompressionsraten liegen hier naturgem&auml;&szlig; etwas h&ouml;her, als bei den reinen Bin&auml;rdateien, da Texte in der Regel mehr wiederholte Byte-Folgen enthalten. Zus&auml;tzlich kommt hier die Komprimierung von <b>Unicode<\/b>-Texten ins Spiel, die ja eine Menge von Null-Bytes enthalten, falls es sich um <b>UTF-16<\/b> handelt. Unser Test-Set enthielt allerdings nur <b>ANSI<\/b>&#8211; oder <b>UTF-8<\/b>-Dateien, und dennoch kamen wir auf Kompressionsraten von bis zu etwa f&uuml;nf &#8211; ein durchaus brauchbarer Wert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/tblTexte.png\" alt=\"Die Datenblattansicht der Tabelle tblTexte zeigt den Ursprungstext der Textdateien neben zus&auml;tzlichen Angaben zur Kompression\" width=\"700\" height=\"96,79012\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Die Datenblattansicht der Tabelle tblTexte zeigt den Ursprungstext der Textdateien neben zus&auml;tzlichen Angaben zur Kompression<\/span><\/b><\/p>\n<h2>Textboxen mit dekomprimierten Texten f&uuml;llen<\/h2>\n<p>Nun befinden sich die Texte komprimiert in der Tabelle und k&ouml;nnten anschlie&szlig;end dekomprimiert wieder als Dateien abgespeichert werden. Eher aber m&ouml;chten Sie sie wahrscheinlich direkt in einem Formular anzeigen. Das Formular <b>frmTexte<\/b> der Beispieldatenbank zeigt, wie das geht. Im Entwurf (Bild 5) finden Sie normale Textboxen f&uuml;r alle Felder der Tabelle vor. Eine Ausnahme bildet das gro&szlig;e ungebundene Textfeld im Detailbereich, bei welchem es sich eben um keine <b>Access-Textbox<\/b> handelt, sondern um ein ActiveX-Steuerelement, die <b>MS Forms-Textbox<\/b>. Sie hat einen gewichtigen Vorteil: Sie kann auch Texte darstellen, die l&auml;nger als 65 kB lang sind. Zudem wirkt sich bei ihr das Scrollen unmittelbar in der Anzeige aus. Sie k&ouml;nnten das Textfeld &uuml;brigens auch &uuml;ber die Eigenschaft <b>Steuerelementinhalt<\/b> direkt an ein Tabellenfeld binden, was hier nat&uuml;rlich entf&auml;llt, weil der Text nach Dekomprimierung aus dem Feld <b>CompressedText<\/b> kommen soll, was erst der VBA-Code erledigt. Leider ein Nachteil der <b>MSForms-Textbox<\/b>: Sie k&ouml;nnen ihr nicht das Feature <b>Verankern<\/b> mit Dehnen verpassen. Wenn Sie das tun, so wirkt sich eine Vergr&ouml;&szlig;erung zur Laufzeit nicht wie erwartet aus: Statt den Textbereich zu vergr&ouml;&szlig;ern, zoomt das Steuerelement lediglich den Text!<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/frmTexte_DS.png\" alt=\"Im Entwurf des Formulars frmTexte kommt eine MS-Forms-Textbox zur Textanzeige zum Einsatz\" width=\"650\" height=\"520,1605\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Im Entwurf des Formulars frmTexte kommt eine MS-Forms-Textbox zur Textanzeige zum Einsatz<\/span><\/b><\/p>\n<p>Den Code zum Dekomprimieren der Daten bringen Sie im Ereignis <b>Beim Anzeigen<\/b> (<b>Form_Current<\/b>) unter:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>\r\n<span style=\"color:blue;\">If <\/span>Me.NewRecord Or <span style=\"color:blue;\">Len<\/span>(Me!CompressedText.Value) = 0<span style=\"color:blue;\"> Then<\/span>\r\n     Me!ctlText.Value = \"\"\r\n     <span style=\"color:blue;\">Exit Sub<\/span>\r\nEnd If    \r\nbin = Me!CompressedText.Value\r\nMe!ctlText.Object.Text = DeCompressRTL(bin)\r\nMe!ctlText.Object.SelStart = 0<\/pre>\n<p>Zun&auml;chst wird hier ermittelt, ob es sich beim angezeigten Datensatz um einen neuen handelt (<b>NewRecord<\/b>) oder, ob das Feld <b>CompressedText<\/b> leer ist. In diesen F&auml;llen wird der Inhalt der Textbox gel&ouml;scht und die Routine verlassen. Andernfalls nimmt das Byte-Array <b>bin<\/b> den Feldinhalt auf und liefert ihn an die Funktion <b>DeCompressRTL<\/b> des Moduls <b>mdlCompression<\/b>. Dessen R&uuml;ckgabewert ist zwar ebenfalls ein Byte-Array, Sie k&ouml;nnen dieses aber interessanterweise direkt der Eigenschaft <b>Text<\/b> des Steuerelements <b>ctlText<\/b> zuweisen. Bei einer Access-Textbox w&auml;re dies nicht m&ouml;glich. Das abschlie&szlig;ende Setzen des Werts f&uuml;r <b>SelStart<\/b> stellt sicher, dass sich der Text-Cursor nach dem Laden des Textes am Anfang steht. Ohne diese Aktion w&uuml;rde sich das Ende des Textes im Steuerelement abbilden.<\/p>\n<p>Zur Laufzeit pr&auml;sentiert sich das Ganze dann wie in Bild 6. Rechts oben im Formular finden Sie einen Button <b>cmdLoad<\/b> vor, &uuml;ber den Sie eine neue Textdatei in einen neuen Datensatz laden k&ouml;nnen. Die ausgel&ouml;ste Ereignisprozedur steht in Listing 5. Sie ist im Grunde analog zur Prozedur <b>ImportsTexts<\/b> und <b>ImportFiles<\/b> (<b>Listing 4<\/b>) ausgef&uuml;hrt, sodass auf weitere Erl&auml;uterungen hier verzichtet werden kann. Nur so viel: Die zu ladende Datei steht in der Variablen <b>sFile<\/b>, nachdem eine Hilfsroutine <b>OpenFileDlg<\/b> in <b>mdlCompression<\/b>, die sich den <b>Office-Filedialog<\/b> zunutze macht, sie ermittelt hat. Am Ende der Prozedur erfolgt noch ein <b>Requery<\/b>, ein Neuladen der Datensatzquelle des Formulars, weil dies wiederum <b>Form_Current<\/b> ausl&ouml;st und den dekomprimierten Text damit zur Anzeige bringt. <b>Requery<\/b> f&uuml;hrt leider zu einem Sprung zum ersten Datensatz des Formulars, weshalb die letzte Zeile &uuml;ber <b>MoveLast<\/b> zum eben angelegten Datensatz zur&uuml;ckspringt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/frmTexte.png\" alt=\"Das Formular frmTexte auf Basis der tblTexte zeigt zur Laufzeit die dekomprimierten Texte an\" width=\"650\" height=\"471,9745\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Das Formular frmTexte auf Basis der tblTexte zeigt zur Laufzeit die dekomprimierten Texte an<\/span><\/b><\/p>\n<h2>Dekomprimierte Dateien im Formular anzeigen<\/h2>\n<p>Handelt es sich bei den komprimierten Daten nicht um Texte, so n&uuml;tzt Ihnen eine Textbox zur Anzeige wenig. Ein <b>Anlage-Steuerelement<\/b> kann ja auch nur Texte und Bilder anzeigen und startet bei anderen Dateitypen nach Doppelklick das mit dem Typ im System assoziierte Programm. Derlei k&ouml;nnten wir hier auch implementieren, doch die Wahl f&auml;llt wieder einmal auf das <b>Webbrowser-Steuerelement<\/b>, da der <b>Internet Explorer<\/b> nicht nur Texte und Bilder anzeigen kann, sondern &uuml;ber Plug-Ins auch andere <b>MIME<\/b>-Typen, wie etwa PDFs oder Videos. Dennoch k&ouml;nnen die dekomprimierten Daten dem Webbrowser nicht einfach als Bin&auml;r-Stream verabreicht werden, sondern m&uuml;ssen zun&auml;chst als Dateien vorliegen. An einer Umwandlung ins Dateisystem kommen Sie hier nicht herum.<\/p>\n<p>Das &uuml;bernimmt im Formular <b>frmBinary<\/b> wieder das Ereignis <b>Form_Current<\/b> (Listing 6). Die komprimierten Daten aus <b>CompressedBLOB<\/b> der Tabelle <b>tblBinary<\/b> speichert das Byte-Array <b>bin<\/b>. Die per <b>DecompressRTL<\/b> erhaltenen Originaldaten nimmt das Ergebnis-Array <b>binOut<\/b> auf. Dessen Inhalt wird in eine im Bin&auml;rmodus ge&ouml;ffnete Datei gespeichert. Der Name dieser Datei (<b>sTempFile<\/b>) ergibt sich aus dem Datenbankpfad plus <b>temp<\/b> plus der zuvor aus dem in <b>Path<\/b> abgelegten vollen Pfad ermittelten Dateiendung in <b>sExt<\/b>. Zu dieser nun erstellten Datei navigiert das Webbrowser-Steuerelement <b>ctlWeb<\/b> und zeigt sie an. Zus&auml;tzlich nimmt die im Kopf des Moduls deklarierte <b>Collection<\/b>-Variable <b>colFiles<\/b> den Namen dieser Datei auf. Denn beim Bl&auml;ttern durch die Datens&auml;tze k&ouml;nnen sich ja so mehrere Dateien wie <b>temp.jpg<\/b>, t<b>emp.pdf<\/b>, oder <b>temp.xls<\/b> im Datenbankpfad ansammeln, die beim Entladen des Formulars besser wieder mit <b>Kill<\/b> gel&ouml;scht und bereinigt werden:<\/p>\n<pre><span style=\"color:blue;\">Private <\/span>colFiles<span style=\"color:blue;\"> As <\/span><span style=\"color:blue;\">New<\/span> VBA.Collection\r\n<span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>, binOut()<span style=\"color:blue;\"> As Byte<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>F<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>sExt<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>sTempFile<span style=\"color:blue;\"> As String<\/span>\r\n     bin = Me!CompressedBLOB.Value\r\n     binOut = DeCompressRTL(bin)\r\n     sExt = <span style=\"color:blue;\">Mid<\/span>(Me!Path.Value, _\r\n         <span style=\"color:blue;\">InStrRev<\/span>(Me!Path.Value, \".\"))\r\n     F = FreeFile\r\n     sTempFile = CurrentProject.Path & \"\\temp\" & sExt\r\n     Open sTempFile For Binary<span style=\"color:blue;\"> As <\/span>F\r\n     Put F, , binOut\r\n     Close F\r\n     DoEvents\r\n     Me!ctlWeb.Object.Navigate2 sTempFile\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     colFiles.Add sTempFile, sExt\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Erstellen tempor&auml;rer Dateien f&uuml;r den Webbrowser-Inhalt<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>itm<span style=\"color:blue;\"> As Variant<\/span>\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     For Each itm In colFiles\r\n         Kill CStr(itm)\r\n     <span style=\"color:blue;\">Next<\/span> itm\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Ein Beispiel, wie sich das Formular zur Laufzeit mit einer aus den komprimierten Daten geladenen <b>PDF<\/b>-Datei pr&auml;sentiert, zeigt Bild 7. Es h&auml;ngt vom <b>PDF-Plugin<\/b> ab, welche Gestalt das Dokument dabei annimmt. Hier ist das &uuml;brigens nicht der <b>Adobe Reader<\/b>, sondern das Plugin des nach unserem Daf&uuml;rhalten besseren <b>PDF-XChange Viewers <\/b>(<b>Tracker Software<\/b>).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/frmBinary.png\" alt=\"Das Formular frmBinary verwendet zur Anzeige der dekomprimierten Dateien einen Webbrowser\" width=\"650\" height=\"473,1012\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Das Formular frmBinary verwendet zur Anzeige der dekomprimierten Dateien einen Webbrowser<\/span><\/b><\/p>\n<h2>Umwandeln von komprimierten Bilddaten in Bilder<\/h2>\n<p>Nat&uuml;rlich k&ouml;nnen Sie Bilder, wie beschrieben, auch mit dem Webbrowser anzeigen oder die jeweils tempor&auml;r exportierte Bilddatei in ein Bildsteuerelement laden. Das ist indessen nicht unbedingt erforderlich, wenn Sie die dekomprimierten Daten direkt in ein Bildobjekt umwandeln und einem <b>MS Forms-Image-Steuerelement<\/b> zuweisen.<\/p>\n<p>Diese Aufgabe ist nicht trivial und kann nur mit-hilfe einer Handvoll von API-Funktionen gel&ouml;st werden. Wir verwenden daf&uuml;r einige Prozeduren auf Basis des Windows-<b>GDIPlus<\/b>, die Sie im Modul <b>mdlGDIPlus<\/b> der Beispieldatenbank vorfinden. Sie &uuml;bergeben der Funktion <b>ArrayToPicture<\/b> ein Byte-Array mit den Bilddaten, die genau der Ursprungsdatei entsprechen m&uuml;ssen. Erlaubte Typen sind <b>BMP<\/b>, <b>JPG<\/b>, <b>PNG<\/b>, <b>TIFF<\/b> und <b>ICO<\/b>. Zur&uuml;ck erhalten Sie ein <b>StdPicture<\/b>-Objekt, das Sie unmittelbar an die Eigenschaft <b>Picture<\/b> eines <b>MS Forms-Images<\/b> leiten k&ouml;nnen. Umgesetzt ist dies im Formular <b>frmBilder<\/b> (s. Bild 8). Beim Laden des Formulars muss zun&auml;chst die <b>GDIPlus-Session<\/b> initialisiert werden (<b>InitGDIP<\/b>-Prozedur):<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2018_01\/frmBilder.png\" alt=\"Das Formular frmBilder zur Anzeige der dekomprimierten Bilddaten verwendet ein Forms-Image\" width=\"650\" height=\"495,7774\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Das Formular frmBilder zur Anzeige der dekomprimierten Bilddaten verwendet ein Forms-Image<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     InitGDIP\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die in der Folge bearbeiteten <b>GDI<\/b>-Objekte sollten beim Entladen des Formulars bereinigt werden:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     ShutDownGDIP\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Der Kern ist dann aber die Ereignisprozedur <b>Beim Laden<\/b>, welche die komprimierten Daten aus der Tabelle holt, sie per <b>DecompressRTL<\/b> in ihren Ursprung zur&uuml;ckverwandelt und das resultierende Byte-Array &uuml;ber <b>ArrayToPicture<\/b> in ein Bildobjekt &uuml;berf&uuml;hrt, welches dem Steuerelement <b>ctlImg<\/b> zugewiesen wird:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Current()\r\n     <span style=\"color:blue;\">Dim <\/span>bin()<span style=\"color:blue;\"> As Byte<\/span>, binOut()<span style=\"color:blue;\"> As Byte<\/span>\r\n     bin = Me!CompressedBLOB.Value\r\n     binOut = DeCompressRTL(bin)\r\n     <span style=\"color:blue;\">Set<\/span> Me!ctlImg.Object.Picture = ArrayToPicture(binOut)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Datenherkunft des Formulars ist ebenfalls die Tabelle <b>tblBinary<\/b>. Nur werden &uuml;ber eine Auswahlabfrage aus ihr nur jene Datens&auml;tze ber&uuml;cksichtigt, die Bilddaten enthalten. Der SQL-Text dazu sieht so aus:<\/p>\n<pre>SELECT * FROM tblBinary\r\nWHERE <span style=\"color:blue;\">Mid<\/span>([Path],<span style=\"color:blue;\">InStrRev<\/span>([Path],\".\")+1)\r\n    In (\"jpg\",\"png\",\"tif\",\"bmp\",\"jpeg\")<\/pre>\n<p>Die Dateiendung wird hier zun&auml;chst aus <b>Path<\/b> und den Funktionen <b>InstrRev<\/b> sowie <b>Mid<\/b> errechnet. Es wird dann per <b>In<\/b>-Operator ermittelt, ob diese in der Mengenaufz&auml;hlung der Klammer enthalten ist. Datens&auml;tze mit anderen Dateiendungen sind damit im Ergebnis nicht mehr pr&auml;sent.<\/p>\n<h2>Zusammenfassung<\/h2>\n<p>Durch die Komprimierung von Texten und Dateien &uuml;ber Windows-API-Funktionen k&ouml;nnen Sie die Gr&ouml;&szlig;e Ihrer Datenbank reduzieren und Traffic in einer Mehrbenutzerumgebung einsparen. Zudem liegen die Dokumente dann in verschl&uuml;sselter Form in den Tabellen vor und sch&uuml;tzen sie damit vor unbefugter Bearbeitung. Der Aufwand f&uuml;r die Implementierung der Routinen ist nicht gro&szlig; und die Beispieldatenbank liefert alles daf&uuml;r Ben&ouml;tigte.<\/p>\n<p>Einige Beispiele im Beitrag <b>HTML5 als Grafikkomponente<\/b> dieser Ausgabe zeigen &uuml;brigens, wie n&uuml;tzlich die Datenkompression sein kann. Dort werden Bilddaten, die <b>Base64<\/b>-kodiert in Tabellen vorliegen, im Umfang deutlich verkleinert.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>Kompression.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/FEBAA189-BE57-402A-B72D-BA9EEAF1CE5E\/aiu_1118.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn Sie l&auml;ngere Texte in Tabellen abspeichern oder umfangreiche Bin&auml;rdaten in OLE-Feldern ablegen, so bl&auml;ht das die Datenbank auf. W&auml;hrend dieser Umstand bei lokalen Datenbanken heutzutage kein Problem mehr darstellt, sieht die Sache in einer Mehrbenutzerumgebung und Netzwerkzugriffen auf Backends schon anders aus. Hier sollte der Traffic minimiert werden. Da macht sich dann die Komprimierung solcher Datenfelder gut, was zu verbesserter Performance f&uuml;hren kann.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[66012018,662018,44000025],"tags":[],"class_list":["post-55001118","post","type-post","status-publish","format-standard","hentry","category-66012018","category-662018","category-VBA_und_Programmiertechniken"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Datenkompression leicht gemacht - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Datenkompression leicht gemacht\" \/>\n<meta property=\"og:description\" content=\"Wenn Sie l&auml;ngere Texte in Tabellen abspeichern oder umfangreiche Bin&auml;rdaten in OLE-Feldern ablegen, so bl&auml;ht das die Datenbank auf. W&auml;hrend dieser Umstand bei lokalen Datenbanken heutzutage kein Problem mehr darstellt, sieht die Sache in einer Mehrbenutzerumgebung und Netzwerkzugriffen auf Backends schon anders aus. Hier sollte der Traffic minimiert werden. Da macht sich dann die Komprimierung solcher Datenfelder gut, was zu verbesserter Performance f&uuml;hren kann.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T21:18:17+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"20\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Datenkompression leicht gemacht\",\"datePublished\":\"2020-05-13T21:18:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/\"},\"wordCount\":3227,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/42a2b805f48e4af0bba865e90a5231f0\",\"articleSection\":[\"1\\\/2018\",\"2018\",\"VBA und Programmiertechniken\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/\",\"name\":\"Datenkompression leicht gemacht - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/42a2b805f48e4af0bba865e90a5231f0\",\"datePublished\":\"2020-05-13T21:18:17+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/42a2b805f48e4af0bba865e90a5231f0\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/42a2b805f48e4af0bba865e90a5231f0\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Datenkompression_leicht_gemacht\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Datenkompression leicht gemacht\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Datenkompression leicht gemacht - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/","og_locale":"de_DE","og_type":"article","og_title":"Datenkompression leicht gemacht","og_description":"Wenn Sie l&auml;ngere Texte in Tabellen abspeichern oder umfangreiche Bin&auml;rdaten in OLE-Feldern ablegen, so bl&auml;ht das die Datenbank auf. W&auml;hrend dieser Umstand bei lokalen Datenbanken heutzutage kein Problem mehr darstellt, sieht die Sache in einer Mehrbenutzerumgebung und Netzwerkzugriffen auf Backends schon anders aus. Hier sollte der Traffic minimiert werden. Da macht sich dann die Komprimierung solcher Datenfelder gut, was zu verbesserter Performance f&uuml;hren kann.","og_url":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T21:18:17+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"20\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Datenkompression leicht gemacht","datePublished":"2020-05-13T21:18:17+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/"},"wordCount":3227,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0","articleSection":["1\/2018","2018","VBA und Programmiertechniken"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/","url":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/","name":"Datenkompression leicht gemacht - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0","datePublished":"2020-05-13T21:18:17+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/42a2b805f48e4af0bba865e90a5231f0"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Datenkompression_leicht_gemacht\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Datenkompression leicht gemacht"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001118","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001118"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001118\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001118"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001118"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001118"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}