Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Datasnap File Upload (https://www.delphipraxis.net/164871-datasnap-file-upload.html)

BeBored 4. Dez 2011 01:13

AW: Datasnap File Upload
 
Danke für deine Hilfe zu so später Stunde. :)
Ich habe deine Änderungen jetzt umgesetzt und mit Server+Client auf einem Rechner funktioniert es auch, aber sobald ich den Server extern öffne und dann übertragen will, gibt es wieder die gleiche Exception. :(

BeBored 4. Dez 2011 01:24

AW: Datasnap File Upload
 
Soweit ich bisher feststellen kann, wird der richtige Dateiname übertragen, aber die Dateien sind immer nur 1024 byte groß.
Die Exception kommt natürlich auch :)

BeBored 4. Dez 2011 01:31

AW: Datasnap File Upload
 
Das ist bisher der Server:
Delphi-Quellcode:
procedure TServerMethods.UploadFile(str: TStream; Store, FileName: string);
var
  aFileStream: TFileStream;
  BytesReadCount: Integer;
  Buffer: array [1 .. 16 * 1024] of Byte;
begin
  if not DirectoryExists(ExtractFilePath(ParamStr(0)) + 'Files\' + Store) then
  begin
    MkDir(ExtractFilePath(ParamStr(0)) + 'Files\' + Store);
  end;
  aFileStream := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'Files\' + Store + '\' + FileName, fmCreate);
  try
    repeat
      BytesReadCount := str.Read(Buffer, BufferSize);
      aFileStream.Write(Buffer, BytesReadCount);
    until (BytesReadCount < SizeOf(Buffer));
    str.Position := 0;
  finally
    aFileStream.Free;
  end;
end;
Und der Client:
Delphi-Quellcode:
procedure TfrmMain.btnSendClick(Sender: TObject);
var
  aFileStream: TFileStream;
  i: Integer;
begin
  if lbFiles.Count > 0 then
  begin
    try
      for i := 0 to lbFiles.Items.Count - 1 do
      begin
        aFileStream := TFileStream.Create(lbFiles.Items[i], fmOpenRead);
        try
          begin
            aClient.UploadFile(aFileStream, Store, ExtractFileName(lbFiles.Items[i]));
            lbFiles.Clear;
          end
        except
          begin
            ShowMessage('Übertragung fehlerhaft!');
          end;
        end;
      end;
    finally
      aFileStream.Free;
      btnSend.Enabled := False;
    end;
  end
  else
  begin
    Konsole.TextHinweis('Keine Dateien zum Senden vorhanden.');
  end;
end;

BeBored 4. Dez 2011 01:40

AW: Datasnap File Upload
 
Grad gesehen das ich ein
Delphi-Quellcode:
SizeOf(Buffer)
vergessen hatte. Nun wird die komplette Datei übertragen und eine Exception gibt es auch nicht mehr.

Vielen Dank für die späte Hilfe! :thumb:

Gor1 10. Jan 2012 10:35

AW: Datasnap File Upload
 
Hallo,

ich habe die Upload-Routine aus dem obigen Beispiel auf Delphi 2009 bzw. Delphi XE2 ausprobiert, allerdings bekomme ich beim zweiten Aufruf der UploadFile-Methode im Client eine Exception (bzw. auch bei der Freigabe des DataSnap-Datenmoduls auf dem Client). Ich habe dann mal die Freigabe des aFileStream im Client auskommentiert, damit funktioniert es dann.
Komischerweise scheint es aber auch keine Speicherlecks (auf dem Client) zu geben, jedenfalls liefert FastMM keine. Irgendwo scheint der Stream also dann doch freigegeben zu werden.

Hier meine Upload-Routine, die mehrfach aufgerufen wird:
Delphi-Quellcode:
   
procedure UploadFile(PfadName, FileName: String);
    var lFileStream: TFileStream;
    begin
      if (FileName <> '') and FileExists(PfadName + FileName) then
      begin
        lFileStream := TFileStream.Create(PfadName + FileName, fmOpenRead);
        try
          try
            DataModule.ServerMethods1Client.UploadFile(lFileStream, 'KundeXY', FileName);
          except
            ShowMessage('Übertragung fehlerhaft!');
          end;
        finally
//        lFileStream.Free;
        end;
      end;
    end;
Hat einer von euch eine Idee, warum das so ist?
Es funktioniert zwar grundsätzlich so, aber es bleibt ein ungutes Gefühl, wenn ein lokales Objekt erzeugt wird aber dann nicht mehr (explizit) freigegeben wird.

himitsu 10. Jan 2012 10:53

AW: Datasnap File Upload
 
Zitat:

Zitat von Gor1 (Beitrag 1145184)
allerdings bekomme ich beim zweiten Aufruf der UploadFile-Methode im Client eine Exception

Wie lautet die Exception-Message (daß man auch immer wieder erts nachfragen muß :wall:) und wie ist die Servermethode implementiert?

irgendwo = Wenn man sagt der Owner soll es machen, dann macht Er (DataSnap) das auch.


Tipp:
Delphi-Quellcode:
procedure UploadFile(PfadName, FileName: String);
    var lFileStream: TFileStream;
    begin
      if (FileName <> '') and FileExists(PfadName + FileName) then
      begin
        lFileStream := TFileStream.Create(PfadName + FileName, fmOpenRead);
        try
          try
            DataModule.ServerMethods1Client.UploadFile(lFileStream, 'KundeXY', FileName);
          except
            ShowMessage('Übertragung fehlerhaft!');
          end;
        finally
          if not DataModule.InstanceOwner then // DataSnap ist hier einfach nur blöd implementiert, also besser so
            lFileStream.Free;
        end;
      end;
    end;
PS: Bei Streams mit (standardmäßig) über 29 KB muß man etwas aufpassen.

PPS:

Eine bessere treffendere Namensgebung wäre auch nicht unbedingt zu verachten. (z.B. alternativ zu den Vorgabewerten DataModule und ServerMethods1Client)

Delphi-Quellcode:
ShowMessage('Übertragung fehlerhaft!');
... Und was lief schief? ... das weiß nun keiner mehr.
stattdessen eventuell sowas:
Delphi-Quellcode:
except
  on E: Exception do
    ShowMessage('Übertragung fehlerhaft!' + sLineBreak + E.Message);
end;

Gor1 10. Jan 2012 12:15

AW: Datasnap File Upload
 
Die Exception-Meldung war "Im Projekt Testprog.exe ist ein Exception der Klasse EExternalException mit der Meldung 'Externe Exception C0000008' aufgetreten".

Die Servermethode ist im Wesentlichen so implementiert wie in dem Beispiel von BeBored oben, aber der Vollständigkeit halber hier nochmal:

Delphi-Quellcode:
procedure TServerMethods1.UploadFile(str: TStream; Store, FileName: String);
var aFileStream: TFileStream;
    BytesReadCount: Integer;
    Buffer: array [1 .. 16 * 1024] of Byte;
    strPfad: String;
begin
  strPfad := CPfad + '\' + Store;
  if not DirectoryExists(strPfad) then
  begin
    MkDir(strPfad);
  end;
  aFileStream := TFileStream.Create(strPfad + '\' + FileName, fmCreate);
  try
    repeat
      BytesReadCount := str.Read(Buffer, SizeOf(Buffer));
      aFileStream.Write(Buffer, BytesReadCount);
    until (BytesReadCount < SizeOf(Buffer));
    str.Position := 0;
  finally
    aFileStream.Free;
  end;
end;
Der Tipp mit der Abfrage nach dem InstanceOwner war sehr hilfreich, sie liefert hier True. Allerdings ist mir nicht klar, warum der InstanceOwner des Streams hier das DataModule ist. Kann man das irgendwo einstellen?

Mit der besseren Namensgebung hast du natürlich recht, aber es ging mir hier erst mal um einen einfachen Test und die korrekte Funktion.

himitsu 10. Jan 2012 12:51

AW: Datasnap File Upload
 
Zitat:

Zitat von Gor1 (Beitrag 1145203)
Der Tipp mit der Abfrage nach dem InstanceOwner war sehr hilfreich, sie liefert hier True.

TRUE ist halt die Standardeinstellung bei dieser automatisch generierten Klasse.

Zitat:

Zitat von Gor1 (Beitrag 1145203)
Allerdings ist mir nicht klar, warum der InstanceOwner des Streams hier das DataModule ist. Kann man das irgendwo einstellen?

Genau dort, wo ich es auch abfrage?
(das ist die globale Einstellung für sowas)

Dieser Wert wird vor den automatisch generierten Clientklassen abgefragt und jeweils für deren Objekt-Parameter verwendet.

Gor1 11. Jan 2012 10:51

AW: Datasnap File Upload
 
Danke für deine Hilfe, ich habe die entsprechenden Stellen jetzt gefunden.

Captnemo 12. Sep 2012 07:53

AW: Datasnap File Upload
 
Hallo,

ich habe mir eure Funktion oben mal zu nutze gemacht um ein Bild zu übertragen. Klappt auch im Großen und Ganzen wunderbar.
Nur habe ich an einer Stelle einen Fehler, den ich mir nicht erklären kann. Hier erst mal mein Code im Client:
Delphi-Quellcode:
procedure TForm2.Button2Click(Sender: TObject);
var
  aClient: TServerMethods1Client;
  aFileStream: TFileStream;
  i: Integer;
 begin
  aClient := TServerMethods1Client.Create(SQLCOnnection1.DBXConnection);
  Try
    aFileStream := TFileStream.Create(JvFilenameEdit1.Text, fmOpenRead);
    try
      aClient.UploadFile(aFileStream, 'Upload', ExtractFileName(JvFilenameEdit1.Text));
    except
      ShowMessage('Übertragung fehlerhaft!');
    end;
  Finally
    aFileStream.Free;
    aClient.Free;
  End;
end;
(Jetzt bitte mal nicht auf die Try...expept-Blöcke achten ;-) )

Wenn ich jetzt was übertragen will, dann tritt beim aClient.Free eine Exception auf:
"Im Projekt DSClient.exe ist eine Exception der Klasse $C0000008 mit der Meldung 'system exception (code 0xc0000008) at
0x77b712f7' aufgetreten."

Ich war eigentlich immer der Meinung, dass man selbst erzeugte Objekte auch selber wieder freigeben sollte. Aber möglicherweise
besteht ja noch ein Zugriff auf dieses Objekt. Ich weiß aber nich wo.

Wenn ich das aClient.Free weglasse, dann habe ich bei XP beim verlassen des Programms eine Exception:
"Exception EAccessViolation in Modul DSClient.exe bei 00005D08.
Zugriffsverletzung bei Adresse 00405D08 in Modul 'DSClient.exe'. Lesen von Adresse 0000000C."

Ich habe noch eine zweite Funktion, die ich aus einen Tutorial übernommen habe:
Delphi-Quellcode:
procedure TForm2.Button1Click(Sender: TObject);
var
  aClient: TServerMethods1Client;
begin
  aClient := TServerMethods1Client.Create(SQLCOnnection1.DBXConnection);
  Try
    Edit1.Text := aClient.ReverseString(Edit1.Text);
  Finally
    aClient.Free;
  End;
 end;
Die läuft aber ohne Exception, und hier gehe ich aClient ja auch frei.

Hat jemand eine Idee, was ich falsch gemacht habe?


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:49 Uhr.
Seite 2 von 3     12 3      

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz