Delphi-PRAXiS
Seite 1 von 3  1 23      

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 3. Dez 2011 18:24

Datasnap File Upload
 
Hallo,
ich sitze in der Arbeit an einer Client/Server Anwendung die wir mit Datasnap realisieren.
Sonst lief auch alles, nur seit heute bekomme ich beim Upload einer Datei eine Exception.
Über einen TOpenDialog wählt man eine Datei. Die wird mit Pfad in eine Listbox eingetragen (lbFiles).
Hier der Client:
Delphi-Quellcode:
aFileStream: TFileStream;
Delphi-Quellcode:
for i := 0 to lbFiles.Items.Count - 1 do
  begin
    aFileStream := TFileStream.Create(lbFiles.Items[i], fmOpenRead);
    if aClient.UploadFile(aFileStream, Store, ExtractFileName(lbFiles.Items[i])) then // Hier exception!
      begin
        Konsole.TextHinweis(ExtractFileName(lbFiles.Items[i]) + ' gesendet!');
      end;
  end;
Die Exception:
Exception-Klasse TDBXError mit Meldung 'Remote-Fehler: Ungültiger Dateiname - %s'.

Der Server:
Delphi-Quellcode:
const
  BufferSize = 1024;
var
  aFileStream: TFileStream;
  Buffer: TBytes;
  BytesReadCount: Integer;
  Success: boolean;
begin
  Success := false;
  if not DirectoryExists(ExtractFilePath(ParamStr(0)) + 'Files\') then
  begin
    MkDir(ExtractFilePath(ParamStr(0)) + 'Files\' + Store);
  end;
  try
    if FileExists(Name) then
    begin
      DeleteFile(Name);
    end;
    aFileStream := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'Files\' + Name, fmCreate);
    SetLength(Buffer, BufferSize);
    repeat
      BytesReadCount := str.Read(Buffer[0], BufferSize);
      if (BytesReadCount > 0) then
        aFileStream.Write(Buffer[0], BytesReadCount);
    until (BytesReadCount < BufferSize);
    str.Position := 0;
    Success := True;
  finally
    aFileStream.Free;
    SetLength(Buffer, 0);
  end;
  Result := Success;
end;
Ich verstehe nicht wo der Fehler liegt, weil gestern noch alles lief...
Hat wer eine Idee?

BeBored 3. Dez 2011 22:52

AW: Datasnap File Upload
 
In der Listbox steht übrigens der richtige Pfad mit der richtigen Datei. Store und Name sind nur für den Server und soweit ich das sehe auch nicht das Problem.

Bummi 3. Dez 2011 23:01

AW: Datasnap File Upload
 
Einzig ungewöhlich finde ich den Parameter "Name"

himitsu 3. Dez 2011 23:05

AW: Datasnap File Upload
 
Jupp, wo "Name" doch ein beliebtes property in allen VCL-Komponenten ist.

Zitat:

Delphi-Quellcode:
MkDir(ExtractFilePath(ParamStr(0)) + 'Files\' + Store)
FileExists(Name)
DeleteFile(Name)
TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'Files\' + Name)


Mit Pfad, ohne Pfad, Pfad mit Store oder Pfad ohne Store?
Delphi-Quellcode:
ExtractFilePath(ParamStr(0)) + 'Files\' + Store
Name
ExtractFilePath(ParamStr(0)) + 'Files\' + Name
PS: Daß die DP Name fett darstellt, sollte dir schon zu Denken geben. :angle2:

BeBored 3. Dez 2011 23:16

AW: Datasnap File Upload
 
Ja stimmt mit Name und habe ich (VNC sei dank) auch gleich geändert aber der Fehler kommt nach wie vor am Client.
Ist Store '00000' dann wird die Datei im Ordner Files gespeichert, ist sie anders (z.B. 52125) dann wird der Ordner 52125 in Files angelegt und die Datei dort gespeichert. Der Server liefert auch kein False zurück, bis dahin kommt er garnicht.

...hab es jetzt gefunden... der Fehler war das ich auf Files geprüft habe aber dann immer Files\00000 anlegen wollte. nenene

Ne das war es doch nicht...

BeBored 3. Dez 2011 23:40

AW: Datasnap File Upload
 
Hier mal die Upload Methode
Delphi-Quellcode:
function TServerMethodsClient.UploadFile(str: TStream; Store: string; fName: string): Boolean;
begin
  if FUploadFileCommand = nil then
  begin
    FUploadFileCommand := FDBXConnection.CreateCommand;
    FUploadFileCommand.CommandType := TDBXCommandTypes.DSServerMethod;
    FUploadFileCommand.Text := 'TServerMethods.UploadFile';
    FUploadFileCommand.Prepare;
  end;
  FUploadFileCommand.Parameters[0].Value.SetStream(str, FInstanceOwner);
  FUploadFileCommand.Parameters[1].Value.SetWideString(Store);
  FUploadFileCommand.Parameters[2].Value.SetWideString(fName);
  FUploadFileCommand.ExecuteUpdate; // Genau hier gibt es dann die Exception
  Result := FUploadFileCommand.Parameters[3].Value.GetBoolean;
end;
Vielleicht hilft es ja :cry:

DeddyH 3. Dez 2011 23:45

AW: Datasnap File Upload
 
Zitat:

Zitat von BeBored (Beitrag 1139199)
Delphi-Quellcode:
FUploadFileCommand.Text := 'TServerMethods.UploadFile';

Sollte es nicht besser LoadFromFile heißen statt der direkten Zuweisung? Ich kann aber auch mal wieder alles falsch verstehen.

BeBored 3. Dez 2011 23:49

AW: Datasnap File Upload
 
Zitat:

Zitat von DeddyH (Beitrag 1139201)
Zitat:

Zitat von BeBored (Beitrag 1139199)
Delphi-Quellcode:
FUploadFileCommand.Text := 'TServerMethods.UploadFile';

Sollte es nicht besser LoadFromFile heißen statt der direkten Zuweisung? Ich kann aber auch mal wieder alles falsch verstehen.

Das wurde von Delphi oder besser von der TSQLConnection erstellt. Das wird auch jedesmal wenn ich eine neue Methode implementiere überschrieben.

DeddyH 3. Dez 2011 23:51

AW: Datasnap File Upload
 
Jo, dann hab ich das wohl falsch interpretiert, ich hab auch ehrlich gesagt keinen Plan von DataSnap.

himitsu 3. Dez 2011 23:53

AW: Datasnap File Upload
 
Delphi-Quellcode:
var
  aFileStream: TFileStream;
  Buffer: array[1..16*1024] of Byte; // 16 KB
  BytesReadCount: Integer;
begin
  if not DirectoryExists(ExtractFilePath(ParamStr(0)) + 'Files') then
    MkDir(ExtractFilePath(ParamStr(0)) + 'Files\' + Store);
  aFileStream := TFileStream.Create(ExtractFilePath(ParamStr(0)) + 'Files\' + FileName, fmCreate);
  try
    repeat
      BytesReadCount := str.Read(Buffer, SizeOf(Buffer));
      aFileStream.Write(Buffer, BytesReadCount);
    until BytesReadCount < SizeOf(Buffer);
  finally
    aFileStream.Free;
  end;
end;
Beschreibung:
  • fmCreate überschreibt bestehende Dateien ... es ist also nicht nötig diese vorher zu löschen
  • Das .Create gehört vor den Try-Finally-Block, denn wenn es vor dem .Create schon knallt, dann knallt es im Finally nochmals beim .Free, da die Variable nicht initialisiert hattest.
    > Tipp: Hör auf das, was dir der Compiler sagt, denn der hat dich ganz bestimmt gewarnt.
    Ausnahme: Man initialisiert die Variable vorher entsprechend mit NIL.
  • Dynamische Arrays (z.B. TBytes) und Strings muß man nicht unbedingt manuell freigeben.
    Vorallem wenn Delphi das eine Millisekune später auch nochmal macht ... Im geheimen/unsichtbaren END-Code deiner Methode.
  • Da du eh mit einer Konstanten Puffergröe arbeitest, kannst du den Puffer auch gleich konstannt erstellen.
    > 16 KB sollten locker nich mit noch auf deinen Stack drauf passen ... wenn nicht, dann stimmt eh irgendwo etwas nicht.
  • 1 KB ist eh etwas "suboptimal"
    DataSnap hat standardmäßig einen Übertragungspuffer von 32 KB und auch die Clustergröße deiner Festplatte (die Größe der Verwaltungseinheiten) wird bei dir bestimmt mehr als ein 1 KB sein.
  • Name > FileName
  • das Success ist vollkommen "sinnlos"
    • Erstemal kannst du deine werte direkt an result übergeben und brauchst keine susätzliche Variable.
      (ist nicht wie beim Return in C, PHP, JS und Co., wo bei dessen Zuweisung die Prozedur beendet wird)
    • außerdem gibt dein Resul keinen "sinnvolen" Wert zurück.
      • es gibt True zurück, wenn alles (vermutlich) erfolgreich war
        (ist nicht wie beim Return in C, PHP, JS und Co., wo bei dessen Zuweisung die Prozedur beendet wird)
      • bei einem Fehler gibt es eine Exception und das Result wird nicht verwendet
      Also reicht eine Proedure ... Fehler werden ja eh als Exception zurückgegeben.

      Die Exceptions jetzt abzufangen (try-except) wäre ganz schlimm, denn ein Boolean sagt nur daß etwas falsch lief,
      aber die Exception, welche gesagt hätte was genau nichtr ging, hätte man dann geschrottet.

      Im Server also einfach
      Delphi-Quellcode:
      procedure UploadFile(Stream: TStream; StorePath, FileName: string);
      verwenden.

PS: Sollte die Datei im Store-Pfad liegen, oder hab ich das falsch verstanden?
Wenn ja, dann muß "Store" natürlich noch mit in den Pfad des TFileStream.Create aufgenommen werden.


Zitat:

Das wird auch jedesmal wenn ich eine neue Methode implementiere überschrieben.
Du mußt das ja auch im Server ändern ... dann wird es im Clienten richtig importiert.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:18 Uhr.
Seite 1 von 3  1 23      

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