Announcement

Collapse
No announcement yet.

Access und Blobfelder

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Access und Blobfelder

    Hallo,<br>
    wenn ich es richtig verstanden habe, muß ich in Access2000 ein OLE-Objekt Feldtyp verwenden, um ein Blobfeld zu erzeugen.<br>
    Tabelle:<br>
    ID : Autowert<br>
    Blob1 : OLE-Objekt<br>
    <br>
    Innerhalb von Access habe ich ein Bild in das Feld Blob1 geschoben. Jetzt möchte ich das Feld mit den nativen ADO Objekten (2.5) lesen und/ oder schreiben.<br>
    Trotz stundenlangen lesen im ADO SDK ist es mir nicht gelungen. Hier mein jämmerlicher Versuch das Feld zu lesen.<br>
    <pre>
    <font face="Verdana" size="1" color="#000000">uses ADODB25_TLB;

    {$R *.DFM}

    resourcestring
    ConnectionString = 'FILE NAME=blob.udl';
    SQLRequest = 'SELECT * FROM Tabelle1';

    procedure TForm1.Button1Click(Sender: TObject);
    var
    ADOConncetion : Connection;
    ADORecordset : Recordset;
    ADOStream : Stream;
    begin
    ADOConncetion:=CoConnection.Create;
    ADORecordset:=CoRecordset.Create;
    ADOStream:=CoStream.Create;
    ADOConncetion.Open(ConnectionString,'','',-1);
    Try
    ADORecordset.Open(SQLRequest,ADOConncetion,adUseSe rver,adLockOptimistic,adCmdUnspecified);
    <b><font face="Verdana" size="1" color="#FF0000">ADOStream.Open(ADORecordset.Fields .Item['Blob1'].Value,adModeRead,adOpenStreamFromRecord,'','');
    </font></b> Finally
    ADORecordset.Close;
    ADOConncetion.Close;
    ADOStream:=Nil;
    ADORecordset:=Nil;
    ADOConncetion:=Nil;
    end;
    end;
    </font></pre>
    In der roten Zeile erhalte ich folgende Fehlermeldung: Die Argumente sind vom falschen Typ, liegen außerhalb des Gültigkeitsbereiches oder sind miteinander unvereinbar.<br>
    Die Frage lautet also: Wie lesen und schreibe ich Blobfelder in einer Access2000 Datenbank mit den nativen ADO (2.5) Objekten.<br>
    Jens Schumann<br>

  • #2
    Hallo,

    das Nachteil an den OLE-Feldern von ACCESS liegt darin, dass dort immer ein 78 Byte-Header davorgeschaltet wird. Will man nun direkt auf die Grafik zugreifen, muss dieser Header übersprungen werden:
    <pre>
    procedure TForm1.ADODataSet1AfterScroll(DataSet: TDataSet);
    var
    aBitmap : TBitmap;
    aBS : TADOBlobStream;
    begin
    if not (ADODataSet1.State in [dsBrowse]) then
    Exit;
    aBS := TADOBlobStream.Create(ADODataSet1Photo, bmRead);
    try
    aBS.Seek(78, soFromBeginning);
    aBitmap := TBitmap.Create;
    try
    aBitmap.LoadFromStream(aBS);
    DBImage1.Picture.Graphic := aBitmap;
    finally
    aBitmap.Free;
    end
    finally
    aBS.Free;
    end;
    end;
    </pre>
    Wenn das Recordset-Objekt bereits geöffnet ist und den Datensatz geladen hat, würde ich auf dem folgenden Weg auf die BLOb-Daten zugreifen. Wird eine neue Instanz des Stream-Objekts erzeugt, kann dieses über die <b>Write</b>-Methode die als Parameter übergebenen Daten in den eigenen Stream schreiben. Ist das erledigt, speichert der Aufruf von <b>SaveToFile</b> diese Streamdaten in einer Datei ab:
    <pre>
    aADOStream := CoStream.Create;
    aADOStream.Type_ := adTypeBinary;
    aADOStream.Open(EmptyParam, adModeUnknown, adOpenStreamUnspecified, '', '');
    aADOStream.Write(aRS.Fields.Item['FileContents'].Value);
    aADOStream.SaveToFile(FSaveFileName, adSaveCreateOverWrite);
    aADOStream.Close;
    <pre&gt

    Comment


    • #3
      Hallo Andreas,<br>vielen vielen Dank für die Antwort.<br>Wenn OLE-Felder in Access den Nachteil der 78 Byte haben, gibt es dann einen besseren Feldtyp für binäre Daten ?<br>Wie schreibe ich denn ein Blobfeld mit den nativen ADO Objekten?<br>Jens Schuman

      Comment


      • #4
        Hallo Andreas,<br>wie man das Feld schreibt habe ich im Forum schon gefunden.<br> ADORecordset.Fields.Item['Blob1'].Value:=ADOStream.Read(adReadAll);<br>
        wie kann ich jetzt z.B. einen TMemoryStream dazu veranlsssen den Inhalt eines ADOStreams zu lesen/laden? Und anderherum, wie kann ich den ADOStream zu veranlassen z.B. einen TMemorystream zu lesen/laden.<br>
        ADOStream.Position:=78;<br>
        ADOStream.SaveToFile(ApplicationPath+'Bild.bmp', adSaveCreateOverWrite);<br>scheint nicht zu klappen. Das Bitmap auf der Platte kann nicht geöffnet werden. Wenn ich die Datei mit einem Hex-Editor anschaue kann ich immer noch Bitmap.Paint PBrush lesen. Das hat sicher nix in einer BMP-Datei zu suchen.<br>
        Jens Schuman

        Comment


        • #5
          Hi, ich denke, das SaveToFile() das komplette Objekt (unabhängig der Streamposition) speichert.

          Besser wäre evtl.:

          <pre>
          var fs: TFileStream;
          ...

          begin
          // ...
          fs:=TFileStream.Create('file'..)
          ADOStream.Seek(78,soFromBeginning);
          fs.CopyFrom(ADOStream);
          fs.Free;
          // ...
          end;
          </pre>

          Auf diese Weise sollte der Header uebersprungen werde

          Comment


          • #6
            Hallo Timo,<br>vielen Dank für Deine Antwort.<br>Leider stehen mir die ADO-Komponenten von Borland <b>nicht</b> zur Verfügung. Daher muß ich mit den nativen ADO-Objekten (denen aus der Typbibliothek) arbeiten. Daher habe ich keinen TADOStream.<br>Wie übergebe ich jetzt den nativen ADO-Stream an einen TMemorystream?<br>Jens Schuman

            Comment


            • #7
              Hallo,<br>
              ich habe heraus gefunden, dass man gar keinen ADOStream braucht, um ein Access OLE-Feld zu lesen.<br>
              Jetzt bin ich mir nur nicht sicher, ob der folgende Code korrekt ist. Er funktioniert zwar, aber ich habe keine<br>
              Erfahrung mit VariantArray's. Könnte mir jemand sagen, ob es so richtig ist ?<br>
              <pre>
              <font face="Verdana" size="1" color="#000000">var
              ADOConncetion : Connection;
              ADORecordset : Recordset;
              Bmp : TBitmap;
              MemoryStream : TMemoryStream;
              V : Variant;
              P : Pointer;
              CountBytes : Integer;
              begin
              Bmp:=TBitmap.Create;
              MemoryStream := TMemoryStream.Create;
              ADOConncetion:=CoConnection.Create;
              ADORecordset:=CoRecordset.Create;
              Try
              ADOConncetion.Open(ConnectionString,'','',-1);
              ADORecordset.Open(SQLRequest,ADOConncetion,adUseCl ient,adLockOptimistic,adCmdUnspecified);
              CountBytes:=ADORecordset.Fields.Item['Blob1'].ActualSize;
              V := VarArrayCreate([0,CountBytes], varByte); // erzeuge ein variantes Array
              V:=ADORecordset.Fields.Item['Blob1'].Value;
              P:=VarArrayLock(V);
              MemoryStream.Write(P^,CountBytes);
              MemoryStream.Seek(72,sofromBeginning); // in Access 2000 scheint der Header nur 72 Byte groß zu sein
              Bmp.LoadFromStream(MemoryStream);
              Image1.Picture.Graphic:=Bmp;
              Finally
              VarArrayUnlock(V);
              Bmp.Free;
              MemoryStream.Free;
              // und aufräumen -&gt;
              ADORecordset.Close;
              ADOConncetion.Close;
              ADORecordset:=Nil;
              ADOConncetion:=Nil;
              end;
              end;</font>
              </pre>
              Jens Schumann<br&gt

              Comment


              • #8
                Hallo Jens,
                In deinem Beispiel, hast Du das Blob-Feld aus der Access-Datenbank mit Hilfe eines Arrays geholt. Läuft gut. Hast Du auch die Möglichkeit ein Blob-Feld in einer Access-Datenbank zu beschreiben ? (Graphik bzw. RTF-Format).
                Danke
                Heinz Hug

                Comment


                • #9
                  Ich will eine Bitmap in einem Blob-Feld abspeichern, so dass diese nachher in Access verwendet werden kann. Dazu muss ich wohl den 72-Byte Header füllen. Weiss jemand was da rein gehört

                  Comment


                  • #10
                    Hallo,

                    &gt;Dazu muss ich wohl den 72-Byte Header füllen.

                    Nicht unbedingt - es hängt davon ab, welche anderen Anwendungen mit diesen Daten arbeiten müssen. Der Hintergrund ist folgender:

                    In einer ACCESS-Datenbank wird der Datentyp <b>OLE-Objekt</b> für das Speichern von beliebigen BLOb-Daten (Binary Large Objects) verwendet. Der OLE-Header (die legendären 78 bzw. 72-Bytes) ist nur dann relevant, wenn die BLOb-Daten über den OLE-Weg dort <b>eingebettet</b> werden.

                    Wenn nur das eigene Programm die BLOb-Daten in der ACCESS-Datenbank einfügt und ausliest, ist der OLE-Header unnötig. In diesem Fall wird nur der binäre Inhalt (Byte-Array) direkt abgelegt. Die ACCESS-Datenbank (genauer gesagt die OLE Objekt-Spalte) ist dann allerdings von anderen Anwendungen aus nicht nutzbar

                    Comment


                    • #11
                      Hallo Herr Kosch,

                      ich habe das Problem, dass ich "Gelegentlich" die gleiche Fehlermeldung bekomme! Soll heißen, dass ich bei 10 Lesevorgängen 1 Mal den Fehler „Die Argumente sind vom falschen Typ, liegen außerhalb des Gültigkeitsbereiches oder sind miteinander unvereinbar.“ bekomme.
                      <br>
                      Meine Konfiguration sieht wie folgt aus:<br>
                      <br>
                      SQL Server 2000 <br>
                      MDAC 2.7 auf den Workstation<br>
                      <br>
                      Nachdem ich das Recordset-Object geöffnet habe und den Datensatz geladen habe greife ich wie folgt auf das BLOB Feld zu:<br>
                      <br>
                      try<br>
                      vTmpADOStream := CoStream.Create;<br>
                      vTmpADOStream.Type_ := adTypeBinary;<br>
                      vTmpADOStream.Open(EmptyParam, adModeUnknown, <br>adOpenStreamUnspecified, '', '');<br>
                      vTmpADOStream.Write(FieldByName('BILD').Value);<br >
                      vTmpADOStream.SaveToFile(vTmpProgPath + MainForm.qBildDaten.FieldByName('KONTONUMMER').AsS tring + '_' + inttostr(vTmpCountBilder) + '.pg' , adSaveCreateOverWrite); <br>
                      finally<br>
                      vTmpADOStream.Close;<br>
                      vTmpADOStream := nil;<br>
                      end;<br>
                      <br>
                      Für Ihre Hilfe oder einen Lösungsansatz wäre ich Ihnen sehr dankbar,<br>
                      <br>
                      Gruss,
                      <br>
                      Ola

                      Comment

                      Working...
                      X