Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > Upload файла на сервер


Автор: Dimich 26.10.2004, 16:12
Доброго времени суток!
Подскажите пожалуйста, как можно средствами Delphi загрузить файл на сервер по ftp? Уже с ног сбился в поиске решения, а так ничего и не нашел...

Автор: MuToGeN 27.10.2004, 11:14
NMFTP вроде компонентина зволась. Еще что-то от Indy было.

Автор: <Spawn> 27.10.2004, 11:25
Попробуй TidFTP.Put.

Автор: Dimich 27.10.2004, 15:41
Спасибо! NMFTP и idFTP вроде работают, вот только я не могу никак через Proxy заставить их работать. В качестве ftp proxy я поставил ESERV 2.99
Я уже запутался с настройками и параметрами этих компонентов. Просьба (не сочтите за наглость) - если будет возможность, киньте кусочек кода разобраться...

Автор: Slawanix 6.1.2005, 23:38
Цитата(Dimich @ 27.10.2004, 16:41)
NMFTP и idFTP вроде работают, вот только я не могу никак через Proxy заставить их работать.

Тема поднималась давно, но чем черт не шутит, по-моему, если коннектишься с фтп через проксю, надо использовать пассивный режим работы с фтпэшником. Как в других прогах Use Passiv FTP

Автор: Dimich 7.1.2005, 17:30
Спасибо за ответ, Slawanix, но к моему сожалению пассивный режим мне ничего не дал. Я уже правда и не могу вспомнить, где у меня конкретно не получилось (надо на работе смотреть). А сама проблема конечно ждет решения, хотя временно отложена мною за наличием более важных в данное время вещей.

Хотя, насколько я помню из моих мучений вышло одно: прокся проксе рознь. Вот в ESERV у меня были проблемы с одним, в других проксях с другим (к сожалению сейчас подробно не могу ничего сказать, т.к. нет под рукой наработок). Но I.E. же у меня через эти прокси работает и ему они побоку!

Еще раз спасибо, Slawanix, за проявленное внимание!

Автор: Slawanix 9.1.2005, 00:07
Цитата(Dimich @ 7.1.2005, 18:30)
А сама проблема конечно ждет решения, хотя временно отложена мною за наличием более важных в данное время вещей.

Dimich, жаль, что это не помогло. Я тоже начал заниматься этой темой, пишу свою прогу. Так что если у меня будет какое-либо решение, тебе сообщу. Просто начал очень недавно, и до этого еще не добрался smile
Добавлено @ 00:11
Цитата
Еще раз спасибо, Slawanix, за проявленное внимание!
. Рад помочь. Мне в нашем форуме всегда помогали...а эта болезнь заразная smile
с уважением, Slawanix.

Автор: RA 9.1.2005, 01:01
А ещё можно использовать компоненты ICS

Автор: Slawanix 9.1.2005, 19:17
А ещё можно использовать компоненты ICS
RAdmin, это делфовские или сторонних разработчиков компоненты?
С уважением, Slawanix.

Автор: RA 9.1.2005, 19:23
Slawanix это самымые лутшие бесплатные дельфовские компоненты
http://www.overbyte.be/

Автор: Slawanix 10.1.2005, 00:10
Цитата
javascript:top.StartDownload('eng', 'arch/icsbeta20050109.zip');

у них эта скриптина на закачку не работает, жаль smile

Автор: RA 10.1.2005, 00:32
http://www.overbyte.be/cgi-bin/redirect.cgi?url=http://www.overbyte.be/arch/icsbeta20050109.zip

Автор: Slawanix 10.1.2005, 00:56
RAdmin, спасибо, уже качаю smile

Автор: RA 26.1.2005, 20:57
Код


uses Wininet;

var
FtpHandle,InetHandle: HInternet;


procedure TForm1.Button1Click(Sender: TObject);
begin
  InetHandle := InternetOpen(PChar('FTP'), 0, nil, nil, 0);
   FtpHandle := InternetConnect(InetHandle, PChar('ftp.server.com'), 21, PChar('UserName'),
       PChar('Password'), INTERNET_SERVICE_FTP, 0, 255);
    if not Assigned(FtpHandle) then
     InternetCloseHandle(InetHandle)
  else

    try
       FtpPutFile(FtpHandle, PChar('LocalFilePath'), PChar('FileNameOnServer'),
       FTP_TRANSFER_TYPE_BINARY, 255);
       except

    end;
 InternetCloseHandle(InetHandle);
end;

Автор: Slawanix 6.2.2005, 02:45
Цитата(Dimich @ 27.10.2004, 16:41)
NMFTP и idFTP

Уважаемые, есть ли у кого-нибудь литература по работе с этими компонентами, а то в книге нет, не от чего оттолкнуться. Помогите, чем смогите, пожалуйста smile

Автор: Akella 16.2.2005, 13:56
Мне кажется, что код RAdmin`а нужно вставить в FAQ и, конечно в DRKB

Автор: Ищущий! 3.6.2005, 22:28
Цитата(RAdmin @ 26.1.2005, 20:57)
Код


uses Wininet;

var
 FtpHandle,InetHandle: HInternet;


procedure TForm1.Button1Click(Sender: TObject);
begin
   InetHandle := InternetOpen(PChar('FTP'), 0, nil, nil, 0);
    FtpHandle := InternetConnect(InetHandle, PChar('ftp.server.com'), 21, PChar('UserName'),
        PChar('Password'), INTERNET_SERVICE_FTP, 0, 255);
     if not Assigned(FtpHandle) then
      InternetCloseHandle(InetHandle)
   else

     try
        FtpPutFile(FtpHandle, PChar('LocalFilePath'), PChar('FileNameOnServer'),
        FTP_TRANSFER_TYPE_BINARY, 255);
        except

     end;
  InternetCloseHandle(InetHandle);
end;

Отличная штука... и тут вопрос... а как узнать прогресс загрузки, сколько загружено и сколько осталось?

Автор: RA 3.6.2005, 23:15
smile
Код


uses Wininet;

var
 FtpHandle,InetHandle: HInternet;
 BytesOut,BytesIn:LongInt;

.......

procedure TForm1.Button1Click(Sender: TObject);
begin
   InetHandle := InternetOpen(PChar('FTP'), 0, nil, nil, 0);
   InternetSetStatusCallback(InetHandle, @InetCallback);

    FtpHandle := InternetConnect(InetHandle, PChar('ftp.server.com'), 21, PChar('UserName'),
        PChar('Password'), INTERNET_SERVICE_FTP, 0, 255);
     if not Assigned(FtpHandle) then
      InternetCloseHandle(InetHandle)
   else

     try
        FtpPutFile(FtpHandle, PChar('LocalFilePath'), PChar('FileNameOnServer'),
        FTP_TRANSFER_TYPE_BINARY, 255);
        except

     end;
  InternetCloseHandle(InetHandle);
end;


procedure InetCallback(HInternet: HINTERNET; dwContext, dwInternetStatus: DWORD;
  lpStatusInfo: Pointer; dwStatusInfoLen: DWORD); stdcall;
begin
  case dwInternetStatus of

    INTERNET_STATUS_REQUEST_SENT:  BytesOut:=BytesOut+DWORD(lpStatusInfo^); {Upload}
    INTERNET_STATUS_RESPONSE_RECEIVED: BytesIn:=bytesIn+DWORD(lpStatusInfo^); {Download}

    {Это сам обрабатывай :) }
    INTERNET_STATUS_RECEIVING_RESPONSE:;
    INTERNET_STATUS_RESOLVING_NAME:;
    INTERNET_STATUS_NAME_RESOLVED:;
    INTERNET_STATUS_CONNECTING_TO_SERVER:;
    INTERNET_STATUS_CONNECTED_TO_SERVER:;
    INTERNET_STATUS_SENDING_REQUEST:;
    INTERNET_STATUS_CTL_RESPONSE_RECEIVED:;
    INTERNET_STATUS_PREFETCH:;
    INTERNET_STATUS_CLOSING_CONNECTION:;
    INTERNET_STATUS_CONNECTION_CLOSED:;
    INTERNET_STATUS_HANDLE_CREATED:;
    INTERNET_STATUS_HANDLE_CLOSING:;
    INTERNET_STATUS_REQUEST_COMPLETE:;
    INTERNET_STATUS_REDIRECT:;
    INTERNET_STATUS_INTERMEDIATE_RESPONSE:;
    INTERNET_STATUS_STATE_CHANGE:;
  end;

end;



Автор: Ищущий! 4.6.2005, 15:21
Типа огромное спасибо... а мож чуть еще помучать Вас smile и всё же... как увидеть процесс загрузки файла в процентах?

Автор: RA 4.6.2005, 16:22
smile smile

Из выше показанного примера следует что

BytesOut - колличество отправленных байт
BytesIn - колличество принятых байт

следовательно что бы сделать прогресс:

{Upload}
//Делим кол-во отправленных байт на Размер твоего файла и умножаем на 100.
//(Ну и округляем это дело)
ProgressBar1.Position:=Round(BytesOut / MyFileSize * 100);
//MyFileSize - кол-во байт d твоем файле, только не спрашивай как узнать сколько //весит твой фаил smile


{Download}
//The same shit.
ProgressBar1.Position:=Round(BytesIn / MyFileSize * 100);
//MyFileSize - кол-во байт в файла на фтпЕ, получаем с помощью
//функции FtpGetFileSize из тогоже winInet.


ЗЫ: "ProgressBar1.Position:= ..." можешь засунуть прям в конец процедуры InetCallback;




Автор: Ищущий! 4.6.2005, 18:42
Цитата(RAdmin @ 4.6.2005, 16:22)
ЗЫ: "ProgressBar1.Position:= ..." можешь засунуть прям в конец процедуры InetCallback;

Спасибо, это то что мне надо было услыхать smile

Автор: RA 4.6.2005, 19:05
Пожал100

Автор: Akella 7.6.2005, 16:12
для получения размера файла, нужно ли его открывать?
типа
Код

 hFile:=WinInet.FtpOpenFile(InetHandle, ...)

Добавлено @ 16:16
что поставить в качестве dwAccess?
Добавлено @ 16:22
нашёл GENERIC_READ

Автор: Akella 7.6.2005, 16:29
а что енто ща второй параметр?
Код

FtpGetFileSize(hFile, ???)

Автор: RA 7.6.2005, 16:34
Цитата(dsergey @ 7.6.2005, 16:12)
для получения размера файла, нужно ли его открывать?
типа


Угу. smile


Кстати можно, получить размер файла через FtpFindFirstFile.

Автор: Akella 7.6.2005, 16:50
Код

InetCallback

в каком месте нужно её вызвать?
Добавлено @ 16:52
Код

procedure TfmSendFiles.ByFtp;
Var
 _iF:integer;
begin
 bbSend.Enabled:=False;
  if uInet.ConnectedToInternet = ctNone then begin
    ShowMessage('Нет подключения к сети интернет');
    exit;
  end;//if
  InetHandle := InternetOpen(PChar('FTP'), 0, nil, nil, 0);
  FtpHandle := InternetConnect(InetHandle,
                                PChar(leFtpAdress.text),
                                StrToInt(leFtpPort.Text),
                                PChar(leFtpUserName.Text),
                                PChar(leFtpPassword.Text),
                                INTERNET_SERVICE_FTP,0,255);
  if not Assigned(FtpHandle) then
    InternetCloseHandle(InetHandle)
  else begin
    FtpSetCurrentDirectory(FtpHandle,PAnsiChar(leFTPDir.Text));
    //пробегаем по списку выбранный файлов
    For _iF:=0 to lvFilesToSend.Items.Count-1 do
      if lvFilesToSend.Items[_if].Checked then
        try
          FtpPutFile(FtpHandle, PChar(fmMain.sPathToSave+lvFilesToSend.Items[_if].Caption),
                     PChar(lvFilesToSend.Items[_if].Caption), FTP_TRANSFER_TYPE_BINARY, 255);
          //в этом месте будет правильно или нет?
        except
          Showmessage('Ошибка отправки файла: '+fmMain.sPathToSave+lvFilesToSend.Items[_if].Caption+
                      'Проверьте наличие файла');
        end;//try-except
  end;//else

 DeleteSended;
 bbSend.Enabled:=True;
 ShowMessage('Готово');
 if cbAutoHungUp.Checked then HungUp;
end;


Я ведь оправляю несколько файлов

Автор: RA 7.6.2005, 20:23
То выше был чисто пример (наверное я этим примеров всех запутал),
на самомо деле стоит разделять отправку, соединение и разъединение.
Код


var //Глобальные переменные
 FtpHandle,InetHandle: HInternet;
 BytesOut,BytesIn:LongInt;

procedure Connect; //Соединение
begin
   InetHandle := InternetOpen(PChar('FTP'), 0, nil, nil, 0);
   InternetSetStatusCallback(InetHandle, @InetCallback);

    FtpHandle := InternetConnect(InetHandle, PChar('ftp.server.com'), 21, PChar('UserName'),
        PChar('Password'), INTERNET_SERVICE_FTP, 0, 255);
     if not Assigned(FtpHandle) then
      InternetCloseHandle(InetHandle);
end;

procedure Disconnect; //Сами понимаете
begin
  InternetCloseHandle(InetHandle);
end;

Function SendFile(Scr, Dest:AnsiString):boolena; 
//Отправка, можно прицепить try except, но не уверен что это может понадобиться
begin
      Result:=  FtpPutFile(FtpHandle, PChar(Scr), PChar(Dest),
        FTP_TRANSFER_TYPE_BINARY, 255);
end;


//Так выглядит отправка, обратите внимание на то как записывается адресс будущего файла на ftp.
 SendFile('C:\1.exe', '/ftpfolder1/folder2/myfile.exe');
   

........


Цитата(dsergey @ 7.6.2005, 16:29)
а что енто ща второй параметр?

код Pascal/Delphi
1:

FtpGetFileSize(hFile, ???)

Упс не заметил этого вопроса.


Тут первым параметром идёт Хендл полученный после вызова FtpOpenFile
второй параметр возвращает размер нашего файла.
var
FSize: Int64;
...
FtpGetFileSize(FileHandle,Fsize);

далее форматируй Fsize.








Добавлено @ 20:25
Цитата(dsergey @ 7.6.2005, 16:50)
в каком месте нужно её вызвать?


После того как получил хэндл от InternetOpen

Добавлено @ 20:29
Цитата(dsergey @ 7.6.2005, 16:50)
  //пробегаем по списку выбранный файлов
    For _iF:=0 to lvFilesToSend.Items.Count-1 do
      if lvFilesToSend.Items[_if].Checked then
        try
          FtpPutFile(FtpHandle, PChar(fmMain.sPathToSave+lvFilesToSend.Items[_if].Caption),
                    PChar(lvFilesToSend.Items[_if].Caption), FTP_TRANSFER_TYPE_BINARY, 255);
          //в этом месте будет правильно или нет?
        except
          Showmessage('Ошибка отправки файла: '+fmMain.sPathToSave+lvFilesToSend.Items[_if].Caption+
                      'Проверьте наличие файла');
        end;//try-except
  end;//else


Плз не пиши таких вещей как lvFilesToSend.Items[_if].Caption и sPathToSave+lvFilesToSend.Items я же не знаю что в них вписанно.

А вобще конструкция вроде рабочая, вот только от try except можно избавиться.

Автор: Ak47t 25.7.2005, 20:52
smile а как при помоши FtpGetFile закачать файл на комп
Опишите пожалуйста если не лень smile

Автор: RA 25.7.2005, 22:48
Код

FtpGetFile(FtpHandle, PChar(FileOnServer), PChar(FileOnLocalDrive),
        True, FILE_ATTRIBUTE_NORMAL, FTP_TRANSFER_TYPE_BINARY or INTERNET_FLAG_RELOAD, 255)

Автор: Ak47t 25.7.2005, 22:59
большое спасибо smile

Автор: Dimich 4.8.2005, 15:25
Сколько времени прошло, пришлось таки вернуться к неразрешенной еще тогда проблемке: работа с ftp через проксю. В качестве прокси стоит на линуксовой машине squid. Собственно это не ftp прокси, а HTTPS с поддержкой FTP. Так может тут какие нюансы есть? Не знаю, поэтому если кто знает, объясните плиз. Но IE работает ведь с ftp, Total Commander тож работает. Как и мне такое сделать (чтоб работало) пока не понял.... Пробовал код Radmin'a - не хочет через проксю соединяться, NMFTP и idFTP тоже не хотят через мою проксю, установил ICS компоненты - та же ситуация.....
Код
  ftpClient1.ConnectionType := ftpProxy;
  ftpClient1.HostDirName := '/';
  ftpClient1.HostName := 'ftp.somehost.ru';
  ftpClient1.UserName := 'myusername';
  ftpClient1.PassWord := 'mypassword';
  ftpClient1.Port := 'ftp';
  ftpClient1.ProxyServer := '192.168.99.3';
  ftpClient1.ProxyPort := '3128';
  ftpClient1.Passive := true;
  ftpClient1.Connect;  // получаю False

Подскажите, как быть? Где я делаю не правильно? Как еще можно решить задачу upload/download файлов на ftp через прокси?

Автор: Dimich 9.8.2005, 16:03
Ситуация развивается следующим образом: решил все делать функциями API, через WinInet. Вот что получилось для Download:
Код
// адаптировано для своих нужд с MSDN
const
  bInitalRequest : bool = TRUE;
Type
  tBuf = array [1..1024] of char;
var
  hConnect, InetHandle: HInternet;
  b : bool;
  dwCode: ^DWORD;
  dwSize: DWORD;
  DUMMY : DWORD;
  dwLength, dWritten : DWORD;
  szBuffer : ^tBuf;
begin
  New (dwCode);
  New (szBuffer);
  InetHandle := InternetOpen(PChar('FTP'),
                             INTERNET_OPEN_TYPE_PRECONFIG,
                             nil,
                             nil,
                             INTERNET_FLAG_KEEP_CONNECTION);
  hConnect := InternetOpenUrl (InetHandle, 'ftp://ftpuser:[email protected]/example.txt', nil, 0,
                                     INTERNET_FLAG_DONT_CACHE or
                                     INTERNET_FLAG_KEEP_CONNECTION or
                                     INTERNET_FLAG_RELOAD, 0);
  if not bInitalRequest then
    if not HttpSendRequest (hConnect, nil, 0, nil, 0) then ShowMessage ('Error: HttpSendRequest');
  dwSize:= sizeof(dwCode^);
  if not InternetQueryOption (hConnect, INTERNET_OPTION_HANDLE_TYPE,
                        dwCode, dwSize) then ShowMessage ('Error: InternetQueryOption');
  if ( (dwCode^ = INTERNET_HANDLE_TYPE_HTTP_REQUEST)  or
       (dwCode^ = INTERNET_HANDLE_TYPE_CONNECT_HTTP) ) then
  begin
    dwSize := sizeof (DWORD) ;
    if not HttpQueryInfo (hConnect, HTTP_QUERY_STATUS_CODE or HTTP_QUERY_FLAG_NUMBER,
                         dwCode, dwSize, DUMMY)
    then
    if dwCode^ = HTTP_STATUS_PROXY_AUTH_REQ then
    begin
      ShowMessage ('Auth Required!');  // доделаю потом, чтобы пройти авторизацию прокси
    end;
  end;
  if dwCode^ <> HTTP_STATUS_PROXY_AUTH_REQ then
  while true do
  begin
     dwLength := SizeOf (szBuffer^);
     if not InternetReadFile (hConnect, szBuffer, dwLength, dWritten) then
     begin
       ShowMessage ('ERROR: InternetReadFile');
       break;
       // delete file
     end;
     if dWritten = 0 then break
     else
     begin
       // Тут собственно пишем буфер в файл
     end;
  end;
  InternetCloseHandle(InetHandle);
  Dispose (dwCode);
  Dispose (szBuffer);

Это работает через прокси замечательно, а вот как закачать файл на ftp сервер? Ответ напрашивается самим собой - InternetWriteFile. Но простая замена Read на Write тут не проходит. GetLastError возвращает ошибку после InternetWriteFile: ERROR_INTERNET_INCORRECT_HANDLE_STATE (12019) - The requested operation cannot be carried out because the handle supplied is not in the correct state.
Смысл ошибки вроде как понятен. А как решить эту задачу не знаю. Знаний маловато.
Собственно читаю http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wininet/wininet/internetwritefile.asp, но реализовать на практике ничего не получается.

Автор: belka 15.12.2006, 12:15
Цитата(RA @  7.6.2005,  20:23 Найти цитируемый пост)
InternetSetStatusCallback(InetHandle, @InetCallback);

что означает @InetCallback?? вернее что значит @???
да и InetCallback?? что все это??
---
сорри за тупой вопрос ))

Автор: Matematik 15.12.2006, 12:32
В ф-ю InternetSetStatusCallback() передается адрес ф-и InetCallback()
InetCallback() - callback ф-я
@ - взять адрес финкции

Автор: belka 15.12.2006, 12:51
Matematik, блин, а можно как-нить поподробнее??
я пробую код RA'dmina, так вот что-то не так получается.. дебагер ругает @InetCallBack - пишет что "Undeclared identifier 'InetCallback'"!! блин.. 
ПОЧЕМУ??

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)