Autor Beitrag
LittleBen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: So 26.08.12 15:44 
Guten Mittag,
ich arbeite zurzeit mit den Funktionen von WinInet und zwar für FTP-Uplaods (bewusst ohne Indy). Jetzt möchte ich gerne den Inhalt eines Memos hochladen und das bestmöglich ohne eine temporäre Datei. Das geht natürlich nur mit einem Stream...Gibt es irgendeinen Weg, einen Stream mit FtpPutFile hochzuladen?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
function FtpPutFile(
    hConnect: HINTERNET;
    lpszLocalFile: PChar;
    lpszNewRemoteFile: PChar;
    dwFlags: DWORD;
    dwContext: DWORD): BOOL;


Noch einen schönen Sonntag und Grüße,
Littleben
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 26.08.12 16:14 
Siehe Dokumentation:
msdn.microsoft.com/e...384170(v=vs.85).aspx hat folgendes geschrieben:
FtpPutFile is a high-level routine that handles all the bookkeeping and overhead associated with reading a file locally and storing it on an FTP server. An application that needs to send file data only, or that requires close control over the file transfer, should use the FtpOpenFile and InternetWriteFile functions.
Einfacher und vor allem plattformunabhängig wäre es natürlich mit z.B. Indy, aber da du das nicht nutzen möchtest...

Indy setzt übrigens nicht auf die API auf sondern kommuniziert direkt mit dem FTP-Server.

Für diesen Beitrag haben gedankt: LittleBen
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: So 26.08.12 21:13 
ahhh ^^ Ok, vielen Dank!
Könntest du mir noch "kurz" sagen, was ich beim Lesevorgang falsch mache?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
procedure UploadData(RemoteFile: string; Data: TMemoryStream);
var hOpen, hUrl: HINTERNET;
    Buffer: array[0..1024of Char;
    BytesRead: dWord;
    Data_written: Cardinal;
begin
 hOpen:= InternetOpen(PChar(FDesc), INTERNET_OPEN_TYPE_PRECONFIG, nilnil0);
 hUrl:= InternetOpenUrl(hOpen, PChar(FHost), nil0, INTERNET_FLAG_RAW_DATA, 0);

 FillChar(Buffer, SizeOf(Buffer), 0);
 repeat
  FillChar(Buffer, SizeOf(Buffer), 0);
  Data.ReadBuffer(Buffer,sizeOf(Buffer));
  InternetWriteFile(hUrl,addr(Buffer),sizeof(Buffer),Data_Written);
 until (Data_Written<=0or (data.Position>=data.Size);

 InternetCloseHandle(hurl);
 InternetCloseHandle(hOpen);
end;

Bekomme dabei den Fehler "Stream-Lesefehler"
Gerd Kayser
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 632
Erhaltene Danke: 121

Win 7 32-bit
Delphi 2006/XE
BeitragVerfasst: Mo 27.08.12 00:03 
user profile iconLittleBen hat folgendes geschrieben Zum zitierten Posting springen:
Bekomme dabei den Fehler "Stream-Lesefehler"


Hast Du vielleicht vergessen, vor dem Lesen aus dem Stream die Position zu setzen?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 27.08.12 07:49 
Das wird es wohl sein, ja. Ich würde die verbleibende Datengröße im Stream aber auch beim Lesen berücksichtigen statt einfach zu versuchen so viele Bytes auszulesen wie in den Puffer passen. ;-)
SvenAbeln
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 334
Erhaltene Danke: 3



BeitragVerfasst: Mo 27.08.12 09:01 
Auch beim Schreiben mit InternetWriteFile sollte die wirkliche Anzahl an Bytes berücksichtigt werden. Im Moment schreibst du immer den kompletten Buffer, auch wenn du z.B. nur ein Byte aus dem Stream gelesen hast.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mo 27.08.12 09:58 
Mhm, die Position vor der Schleife zu setzten hat auch nichts gebracht...ein Seek-Befehl genau so nicht.

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
procedure UploadData(RemoteFile: string; Data: TMemoryStream);
var hOpen, hUrl: HINTERNET;
    Buffer: array[0..1024of Char;
    BytesRead: dWord;
    Data_written: Cardinal;
begin
 hOpen:= InternetOpen(PChar(FDesc), INTERNET_OPEN_TYPE_PRECONFIG, nilnil0);
 hUrl:= InternetOpenUrl(hOpen, PChar(FHost), nil0, INTERNET_FLAG_RAW_DATA, 0);

 Data.Position:= 0;
 //Data.Seek(0,soFromBeginning);
 FillChar(Buffer, SizeOf(Buffer), 0);
 repeat
  FillChar(Buffer, SizeOf(Buffer), 0);
  Data.ReadBuffer(Buffer,sizeOf(Buffer));
  InternetWriteFile(hUrl,addr(Buffer),sizeof(Buffer),Data_Written);
 until (Data_Written<=0or (data.Position>=data.Size);

 InternetCloseHandle(hurl);
 InternetCloseHandle(hOpen);
SvenAbeln
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 334
Erhaltene Danke: 3



BeitragVerfasst: Mo 27.08.12 13:11 
ReadBuffer prüft ob genau die angegebene Anzahl Bytes gelesen wurde und gibt sonst einen "Stream-Lesefehler". Falls du also nicht genau 1025 Char in deinem Stream hast, wirst du so immer diesen Fehler bekommen.
Read liest einfach die Bytes und gibt dabei keinen Fehler aus.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mo 27.08.12 14:17 
Ok, ein Fehler bekomm ich nun nicht mehr, aber es wird komischerweise nichts ausgelesen?

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
var hOpen, hUrl: HINTERNET;
    BufferIn : INTERNET_BUFFERS;
    Buffer: array[0..1024of Byte;
    TmpStream: TMemoryStream;
    cURL: string;
    Size: integer;
    BytesWritten: cardinal;
begin
 TmpStream:= TMemoryStream.Create;
 Form1.Memo1.lines.SaveToStream(TmpStream);
 cURL:= 'http://test.de/test.dat';

 hOpen := InternetOpen('Test', INTERNET_OPEN_TYPE_PRECONFIG, nilnil0);
 hUrl := InternetOpenUrl(hOpen, PChar(cURL), nil0, INTERNET_FLAG_RAW_DATA, 0);

 try
  BufferIn.dwBufferTotal:= TmpStream.Size;
  Size:= TmpStream.Read(Buffer, 1024);
  // Size = 0
  InternetWriteFile(hUrl, @Buffer, size, BytesWritten);

  while (BytesWritten = Size) and (BytesWritten > 0do
  begin
   size:= TmpStream.Read(Buffer, 1024);
   InternetWriteFile(hUrl, @Buffer, Size, BytesWritten);
  end;
 finally
  TmpStream.Free;

  InternetCloseHandle(hUrl);
  InternetCloseHandle(hOpen);
 end;
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mi 29.08.12 13:55 
Hier nun die funktionierende Funktion:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
function TUploader.UploadData(Source: string; RemoteFile: string): boolean;
var hOpen, hConnect, hFile: HINTERNET;
    Size: integer;
    Index: integer;
    toWrite: cardinal;
    BytesWritten: cardinal;
const Blocksize = 1024;
begin
 hOpen:= InternetOpen(PChar(FDesc), INTERNET_OPEN_TYPE_DIRECT, nilnil0);
 hConnect:= InternetConnect(hOpen, PChar(FHost), FPort, PChar(FUsername), PChar(FPassword), INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);
 hFile:= FtpOpenFile(hConnect, PChar(RemoteFile), GENERIC_WRITE, FTP_TRANSFER_TYPE_BINARY, 0);
 try
  if Assigned(hFile) then
  begin
   Size:= Length(Source);
   Index:= 1;
   repeat
    toWrite:= Size - Index + 1;
    if toWrite>Blocksize then
     toWrite:= Blocksize;
    BytesWritten:= 0;
    if InternetWriteFile(hFile,@source[Index],toWrite,BytesWritten) then
     inc(Index,BytesWritten);
   until (BytesWritten < Blocksize) or (Index>Size);
   result:= true;
  end;
 finally
  InternetCloseHandle(hFile);
  InternetCloseHandle(hConnect);
  InternetCloseHandle(hOpen);
 end;
end;

Hat jemand eine Idee, wie ich den String nur hinzufügen kann ohne die Datei komplett zu überschreiben (also Append)? Erst auslesen und dann wieder komplett schreiben ist nicht ideal, da der Upload nicht gerade der schnellste ist...

SOLVED: support.microsoft.com/kb/182316/de
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 29.08.12 19:39 
Das ganze liest sich so als ob du gar kein FTP brauchst, sondern eher ein Skript auf dem Server, das die Datei schreibt...

Dann hast du auch nicht das Problem, dass du die Logindaten mit dem Programm mitliefern musst, was bei FTP ja unumgänglich ist. (Die lassen sich da ja blitzschnell auslesen, egal was du machst.)
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mi 29.08.12 19:43 
Mhm, stimmt. Also wäre es eine Alternative einfach via Post die Daten an eine PHP-Datei zu schicken?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 29.08.12 20:12 
Richtig. Da kann dann zumindest nicht viel passieren, wenn jemand die Datei herausfindet, er kann höchstens die Datei vollmüllen.

Zudem ist es sehr viel einfacher.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mi 29.08.12 20:27 
Okay, das werde ich nacher gleich mal probieren. Davor würde ich trotzdem noch gerne die Geschichte mit dem FTP zuende bringen, es ist ja eigentlich nicht mehr weit vom Ziel entfernt ^^ Der folgende Code gibt ein Error beim FtpCommand aus. Um genauer zu sein den Errorcode 12003, was folgendes bedeutet:
Zitat:
ERROR_INTERNET_EXTENDED_ERROR
Vom Server wurde ein erweiterter Fehler zurückgegeben. Hier handelt es sich in der Regel um eine Zeichenfolge oder einen Puffer, der eine ausführliche Fehlermeldung enthält.

Rufen Sie "Call InternetGetLastResponseInfo" auf, um den
Fehlertext zu erhalten.
Als InternetGetLastResponseInfo bekomme ich zurück:
Zitat:
200 Type set to A
227 Entering Passive Mode (210,202,225,203,197,39)
451 Test.dat: Append/Restart not permitted, try again
Weiß jemand, an was das liegt? Muss ich mich anderst anmelden?

CODE:
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
var hOpen, hConnect, hFile: HINTERNET;
    Size: integer;
    Index: integer;
    toWrite: cardinal;
    BytesWritten: cardinal;
    dwError : DWord;
    szBuffer : PChar;
    dwSize  : DWord;
const Blocksize = 1024;
begin
 hOpen:= InternetOpen(PChar(FDesc), INTERNET_OPEN_TYPE_DIRECT, nilnil0);
 hConnect:= InternetConnect(hOpen, PChar(FHost), FPort, PChar(FUsername), PChar(FPassword), INTERNET_SERVICE_FTP, INTERNET_FLAG_PASSIVE, 0);

 if Append then
  if Assigned(hConnect) then
   if not FtpCommand(hConnect, true, FTP_TRANSFER_TYPE_ASCII, PChar('APPE '+RemoteFile), 0then
   begin
    showmessage(inttostr(GetLastError));
    dwSize:= 255;
    szBuffer:= StrAlloc(dwSize);
    try
     InternetGetLastResponseInfo(dwError, szBuffer, dwSize);
     showmessage(szBuffer);
    finally
     StrDispose(szBuffer);
    end;
   end;

 hFile:= FtpOpenFile(hConnect, PChar(RemoteFile), GENERIC_WRITE, FTP_TRANSFER_TYPE_BINARY, 0);
 try
  if Assigned(hFile) then
  begin
   Size:= Length(Source);
   Index:= 1;
   repeat
    toWrite:= Size - Index + 1;
    if toWrite>Blocksize then
     toWrite:= Blocksize;
    BytesWritten:= 0;
    if InternetWriteFile(hFile,@source[Index],toWrite,BytesWritten) then
     inc(Index,BytesWritten);
   until (BytesWritten < Blocksize) or (Index>Size);
   result:= true;
  end;
 finally
  InternetCloseHandle(hFile);
  InternetCloseHandle(hConnect);
  InternetCloseHandle(hOpen);
 end;
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 29.08.12 22:31 
Du musst dies am FTP-Server konfigurieren. Standardmäßig ist das oft deaktiviert.
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Mi 29.08.12 23:08 
Mhm, ich habe als Testserver einen FTP-Server bei Ohost. Der Support behauptet es liege am Client. Man kann sonst auch nichts am Server einstellen... :(

EDIT: Hab hier noch etwas interessantes gefunden, kann es aber nicht richtig deuten ^^
Zitat:
Syntax: APPE remote-filename

Append data to the end of a file on the remote host. If the file does not already exist, it is created. This command must be preceded by a PORT or PASV command so that the server knows where to receive data from.
www.nsftools.com/tips/RawFTP.htm#APPE
Zitat:
Syntax: PORT a1,a2,a3,a4,p1,p2

Specifies the host and port to which the server should connect for the next file transfer. This is interpreted as IP address a1.a2.a3.a4, port p1*256+p2.
www.nsftools.com/tips/RawFTP.htm#PORT
Zitat:
Syntax: PASV

Tells the server to enter "passive mode". In passive mode, the server will wait for the client to establish a connection with it rather than attempting to connect to a client-specified port. The server will respond with the address of the port it is listening on, with a message like:
227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
where a1.a2.a3.a4 is the IP address and p1*256+p2 is the port number.
www.nsftools.com/tips/RawFTP.htm#PASV
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 30.08.12 09:34 
Also ich kann es auf meinem dedicated Server einstellen und auf meinem Webspace wird das unterstützt, habe es bei 3 Servern ausprobiert (nicht mit dem Quelltext, auf der Konsole). ;-)
Bei einem Freehoster brauchst du dich nicht wundern... die paar Euro würde ich schon investieren.

Aber davon abgesehen ist die andere Lösung doch in 20 Minuten fertig und sowieso sinnvoller. ;-)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 30.08.12 09:36 
// EDIT: Doppelpost...
LittleBen Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 258
Erhaltene Danke: 4

Win 7, Mac OS
Delphi 7
BeitragVerfasst: Do 30.08.12 11:49 
Nagut, dann lass ich das mit dem FTP sein ^^ Zudem ist die Parameterliste in WinInet auch noch falsch...der letzte Parameter fehlt.
Gibt es eine begrenzte Datenmenge die man mit Post übermitteln kann? Und fallen am Server nicht noch größere Lasten an, wenn alles noch über eine PHP-Datei geht?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19273
Erhaltene Danke: 1740

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 30.08.12 12:26 
user profile iconLittleBen hat folgendes geschrieben Zum zitierten Posting springen:
Zudem ist die Parameterliste in WinInet auch noch falsch...der letzte Parameter fehlt.
Bei Delphi 7, ja. In aktuellen nicht soweit ich das sehe. ;-)

user profile iconLittleBen hat folgendes geschrieben Zum zitierten Posting springen:
Gibt es eine begrenzte Datenmenge die man mit Post übermitteln kann?
Nicht direkt. Ein Timeout wäre möglich, wenn es zu lange dauert, je nach Servereinstellung. Größere Datenmengen würde ich aber als Dateiupload hochladen, da gehen je nach Server mind. 1 MiB, bei "echten" Hostern bis zu 30 oder so.

user profile iconLittleBen hat folgendes geschrieben Zum zitierten Posting springen:
Und fallen am Server nicht noch größere Lasten an, wenn alles noch über eine PHP-Datei geht?
PHP-Zugriffe sind das Normale, FTP-Zugriffe nicht. Deshalb ist es wohl eher umgekehrt, zumal das PHP-Skript gut optimieren kann.