Конференция "Сети" » Отправка и приём файлов в FTP сервер [D7, WinXP]
 
  • Xmen (15.11.11 08:25) [0]
    Привет мастерам!
    Нужна сделать прогу для отправки и приёму файлов в FTP сервер. Нужно сделать так чтобы по таймеру обновлял файлы(отправка/приём). Этакое маленькое служба почты. Нашел пример и по примеру сделал процедуру
    отправка
    procedure FTPUpload();
    var IdFTP:TIdFtp;
       dn:integer;
       F: TSearchRec;
    begin
     try
       IdFTP:=TIdFTP.Create(nil);
       if IdFTP.Connected then
         begin
          IdFTP.Abort;
          IdFTP.Quit;
         end;
       IdFTP.Username := UserName;
       IdFTP.Password := UserPass;
       IdFTP.Host := FTPIp;
       try
          IdFTP.Connect;
          if IdFTP.Connected then
            begin
             IdFTP.ChangeDir('/Send');
             chdir('D:\Send\');
             dn := FindFirst('*.*',faArchive,F);
             while dn = 0 do
               begin
                 IdFTP.Put('D:\Send\'+f.name,f.name);
                 dn := FindNext(F);
               end;
             IdFTP.Quit;
            end;
          ShowMessage('Загрузка завершена.');  
       except
          ShowMessage('Ошибка отправки.');
       end;
     finally
       IdFTP.Free;
     end;
    end;



    приём
    procedure FTPDownload();
    var IdFTP:TIdFtp;
       dn:integer;
       F: TSearchRec;
    begin
     try
       IdFTP:=TIdFTP.Create(nil);
       if IdFTP.Connected then
        begin
          IdFTP.Abort;
          IdFTP.Quit;
        end;
       IdFTP.Username := UserName;
       IdFTP.Password := UserPass;
       IdFTP.Host := FTPIp;
       try
          IdFTP.Connect;
          if IdFTP.Connected then
            begin
             IdFTP.ChangeDir('/Recv');
             //chdir('D:\Recv\');
             dn := FindFirst('*.*',faArchive,F);
             while dn = 0 do
               begin
                 IdFTP.Get(f.name, 'D:\Recv\'+f.name);
                 dn := FindNext(F);
               end;
             IdFTP.Quit;
            end;
          ShowMessage('Прём файлов завершен.');
       except
          ShowMessage('Ошибка приёма.');
       end;
     finally
         IdFTP.Free;
     end;
    end;



    Довнлоад каталога не получается  по имени файла нормально получается.  
    И как нужно правильно организовать работу с FTP сервером
  • Сергей М. © (15.11.11 09:06) [1]
    Либо проблем нет либо они есть и вполне конкретные.
    А "не получается" - в программировании нет такого слова)
  • Anatoly Podgoretsky © (15.11.11 09:56) [2]
    > Xmen  (15.11.2011 08:25:00)  [0]

    Я в растерянности, то получается, то нет

    > не получается  по имени файла нормально получается.
  • Xmen (15.11.11 10:18) [3]
    Изменяюсь за то что конкретно не описал задачу и проблему.
    У меня получается Upload каталога а Download каталога не работает. Одного файла скачать получился по имени файла  а несколько файлов не получился

    dn := FindFirst('*.*',faArchive,F);
            while dn = 0 do
              begin
                IdFTP.Get(f.name, 'D:\Recv\'+f.name);
                dn := FindNext(F);
              end;


    не работает.  IdFTP.Get('1.doc', 'D:\Recv\1.doc'); работает.
    У меня обработка каталога не получился.
    И вопрос я ранше не работал с FTP, как работает докачка файла.
  • Anatoly Podgoretsky © (15.11.11 11:23) [4]
    > Xmen  (15.11.2011 10:18:03)  [3]

    Странно однако, в FindFirst *.*, а в Get f.name

    Спрашивается зачем же нужен FindFirst если оно не используется, кроме того
    неужели ты думаешь что в папке может быть более одного файла с одинаковым
    имением, ты просто оптимист.

    Да и справка говорит, что такого прототива вызова нет. Второй параметр
    должен быть потоком
  • clickmaker © (15.11.11 11:51) [5]
    > Download каталога не работает

    FindFirst вообще-то функция для локальной ФС. Какое отношение она к download имеет?
  • Anatoly Podgoretsky © (15.11.11 12:22) [6]
    То то у меня справка нашла, а надо для Инди, а там такой функции нет
  • Плохиш © (15.11.11 12:46) [7]

    > Xmen   (15.11.11 10:18) [3]
    >
    > Изменяюсь за то что конкретно не описал задачу и проблему.
    >
    > У меня получается Upload каталога а Download каталога не
    > работает.

    Так как он может работать? Файлы у тебя лежат на сервере, а список ты ищеш локально.
    TidFtp.List + F1
  • Xmen (15.11.11 13:05) [8]
    Вот поэтому и спрашивал
    TidFtp.List нашел
    и пример автор которого Куликов Алексей после изменения код такой

    procedure Download;
    var
     IdFTP:TIdFtp;
     Path: string;
     FileList :  TStringList;
     jj: Integer;
    begin
     IdFTP:=TIdFTP.Create(nil);
       if IdFTP.Connected then
        begin
          IdFTP.Abort;
          IdFTP.Quit;
        end;
     IdFTP.Username := UserName;
     IdFTP.Password := UserPass;
     IdFTP.Host := FTPIp;
     Path := 'D:\Recv\';
     try
       IdFTP.Connect();
       idFTP.ChangeDir('/Recv');
       try
         FileList := TStringList.Create;
         idFTP.List(FileList,'*.*',False);
         for jj := 0 to FileList.Count-1 do
         begin
           try
             idFTP.Get(FileList[jj], Path + FileList[jj], True);
           except
             on E: Exception do
               ShowMessage(Format('Ошибка скачивания',[FileList[jj], E.ClassName, E.Message]));
           end;
         end;
       finally
         FreeAndNil(FileList);
       end;

       IdFTP.Disconnect
     except
       on E: Exception do
         showmessage('Error!'#13#10+E.Message);
     end;


    И как организовать докачку  файла.
  • Anatoly Podgoretsky © (15.11.11 13:18) [9]
    В протоколе команды rest/reget

    В инди смотри сначала resime/restpos
  • Xmen (15.11.11 14:38) [10]
    IdFTP1.ResumeSupported Это?
  • Anatoly Podgoretsky © (15.11.11 14:48) [11]
    > Xmen  (15.11.2011 14:38:10)  [10]

    Там в справке все хорошо описано.
  • Xmen (15.11.11 15:32) [12]
    изменил код на это
    idFTP.Get(FileList[jj], Path + FileList[jj], False, True);
    Теперь правильно?
  • Xmen (15.11.11 16:57) [13]
    Вот другая ошибка при Upload е получил такую ошибку. Файл был где то 50 мегабайтов. Загрузил 9 мегабайтов и получил ошибку. Докачка не получился
    Socket Error #10054 Connection reset by per
  • Xmen (16.11.11 07:54) [14]
    Воспользовался примером
     Demo Name:  FTP Client Demo
     Created By: Doychin Bondzhev
             On: 27/10/2002
     Notes:
       FTP Client Demo

    и он тоже вернул ошибку
    Socket Error #10054 Connection reset by per
    Где может быт ошибка, как можно решит проблему?
  • Сергей М. © (16.11.11 10:10) [15]
    Возьми на вооружение модуль ftpsend из состава Synapse и не мучайся
  • Anatoly Podgoretsky © (16.11.11 10:33) [16]
    > Xmen  (16.11.2011 07:54:14)  [14]

    Connection reset by peer это не ошибка, а нормальная работа протокола.
  • Xmen (16.11.11 11:18) [17]

    > Anatoly Podgoretsky ©   (16.11.11 10:33) [16]
    > > Xmen  (16.11.2011 07:54:14)  [14]Connection reset by peer
    > это не ошибка, а нормальная работа протокола.

    Это я понял вот как мне сделать так чтобы снова соединяется с сервером.
    IdFTP1.Disconnect;
    IdFTP1.Socket.Close;
    IdFTP1.Connect;
    Не получился дала ошибку.

    > Сергей М. ©   (16.11.11 10:10) [15]
    > Возьми на вооружение модуль ftpsend из состава Synapse и
    > не мучайся

    Это отдельная компонента?
    И вопрос как правильно организовать работу с FTP сервером. Я так понял что могут быть обрыв связи, докачка файла итд.
    Есть ли другой компонент лучший чем Indy, простой в использование а то я по гуглу нетак много нашел. Indy in Depth - не про этот компонент :)
  • Сергей М. © (16.11.11 11:39) [18]

    > Это отдельная компонента?


    Это вообще не "компонента".
    В юните ftpsend.pas есть довольно подробные комментарии по использованию класса TFtpSend
  • clickmaker © (16.11.11 12:14) [19]
    Indy тоже вполне нормально может работать.
    Но у разных фтп-серваков есть свои нюансы. Н-р, кто-то разрешает только пассивный режим и т.п.
  • Anatoly Podgoretsky © (16.11.11 12:24) [20]

    > Xmen   (16.11.11 11:18) [17]

    Трудно назвать Инди лучшим.
  • Anatoly Podgoretsky © (16.11.11 12:25) [21]

    > Indy тоже вполне нормально может работать.

    Но не у всех это получается.
  • Сергей М. © (16.11.11 12:29) [22]

    > Трудно назвать Инди лучшим


    "Эт точно" (с) Ф.Сухов

    Трижды подумать надо, прежде чем тянуть в проект этого глюкавого монстра ради тривиальной задачи под конкретную платформу
  • Xmen (18.11.11 14:48) [23]

    > Сергей М. ©   (16.11.11 11:39) [18]
    > > Это отдельная компонента?Это вообще не "компонента".В
    > юните ftpsend.pas есть довольно подробные комментарии по
    > использованию класса TFtpSend


    на этом юните сделал отправку и приём файлов.
    procedure TForm1.Button7Click(Sender: TObject);
    var dn, i:integer;
       F: TSearchRec;
    begin
      i:=0;
      chdir('D:\Send\');
      dn := FindFirst('*.*',faArchive,F);
      while dn = 0 do
        begin
          FTPClient.DataStream.LoadFromFile(f.Name);
          FTPClient.StoreFile(ExtractFileName(FTPClient.GetCurrentDir+'\Send\'+f.Name),false);
          FTPClient.
          DeleteFile(f.Name);
          Memo1.Lines.Add('Çàãðóæåí ôàéë: '+F.Name+' âðåìÿ çàêà÷êè: '+datetimetostr(NOW));
          inc(i);
          dn := FindNext(F);
        end;
     Memo1.Lines.Add('Óñïåøíî çàêà÷àííûõ ôàéëîâ: '+inttostr(i));
     refreshDir;
    end;

    procedure TForm1.Button8Click(Sender: TObject);
    var i:integer;
    begin
     for i := 0 to FTPClient.FtpList.Count-1 do
      begin
        try
          FTPClient.RetrieveFile(FTPClient.GetCurrentDir+'\Recv\'+FTPClient.FtpList[i].FileName,false);
          FTPClient.DataStream.SaveToFile('D:\RECV\'+FTPClient.FtpList[i].FileName);
          FTPClient.DeleteFile(FTPClient.GetCurrentDir+'\Recv\'+FTPClient.FtpList[i].FileName);
          Memo1.Lines.Add('Ñêà÷àí ôàéë: '+FTPClient.FtpList[i].FileName+' âðåìÿ: '+datetimetostr(NOW));
        except
          on E: Exception do ShowMessage('Îøèáêà ïðè ñêà÷èâàíèè ôàéëà %s'#13#10'class:%s'#13#10'%s'+FTPClient.FtpList[i].FileName);
        end;
      end;
     Memo1.Lines.Add('Óñïåøíî ñêà÷àííûõ ôàéëîâ: '+inttostr(FTPClient.FtpList.Count));
     refreshDir;
    end;

    Теперь нужно организовать процесс процента закачки и скачки через прогрессбар. Как это можно сделать в ftpsend е
  • Сергей М. © (18.11.11 15:17) [24]
    unit blcksock
    ..
    TBlockSocket
    ..
       {:This event is called by various reasons. It is good for monitoring socket,
        create gauges for data transfers, etc.}
       property OnStatus: THookSocketStatus read FOnStatus write FOnStatus;
  • Xmen (18.11.11 16:18) [25]

    > Сергей М. ©   (18.11.11 15:17) [24]
    > unit blcksock..TBlockSocket..    {:This ev
    stacktrace: n/a; see  opera:config#UserPrefs|Exceptions Have Stacktraceent is called
    > by v
    stacktrace: n/a; see  opera:config#UserPrefs|Exceptions Have Stacktracearious reasons. It is good for monitoring socket,  
    >   create gauges for data transfers, etc.}    property OnStatus:
    >  THookSocketStatus read FOnStatus write FOnStatus;


    Спасибо.
    как это в коде реализовать?
    (уже начинаю тупеть)
  • Xmen (13.12.11 14:55) [26]
    Вновь вернулся на этот вопрос.
    Создал код и оно работает. Но не могу понять вот если соединения разорвался в ФТП отправлен файл но не полностью как там в ФТП узнать что этот файл неполный то есть я должен скопировать эту папку с файлами и не должен скопировать такие файлы.
  • Anatoly Podgoretsky © (13.12.11 15:10) [27]
    По протоколу разрыв соединения есть признак окончания передачи. Поэтому на FTP серверах рядом с файлом помещают файл с контрольной суммой.
  • Xmen (13.12.11 15:14) [28]

    > Anatoly Podgoretsky ©   (13.12.11 15:10) [27]
    > По протоколу разрыв соединения есть признак окончания передачи.
    >  Поэтому на FTP серверах рядом с файлом помещают файл с
    > контрольной суммой.

    Сейчас проверю
  • Xmen (13.12.11 15:19) [29]
    Сервер FileZila клиент Total отправил 2 гига файла и отменил копирование. Поискал этот файл с контрольной суммой но не нашел. Где искать надо?
    У меня есть клиент на Delphi.
  • Anatoly Podgoretsky © (13.12.11 15:26) [30]
    Ты его сам должен послать, автоматом это не делается.
  • Xmen (13.12.11 15:40) [31]
    То есть как?
    Путём сравнения файла?
    Помогите еще ...
  • Anatoly Podgoretsky © (13.12.11 16:00) [32]
    > Xmen  (13.12.2011 15:40:31)  [31]

    Очень просто, на сервер отсылаются два файла, а при считывании расчитывается
    новая контрольная суммв, если она не совпадает, то ошибка передачи.
  • Xmen (13.12.11 16:14) [33]
    То есть я сначала пишу контрольную сумму в файл и скопирую файл с текстом контрольной суммой в FTP. Потом идет сравнение файла.
  • Anatoly Podgoretsky © (13.12.11 16:25) [34]
    > Xmen  (13.12.2011 16:14:33)  [33]

    Нет файлы (оба) тоже надо отправить на сервер
  • Xmen (13.12.11 16:44) [35]

    > Anatoly Podgoretsky ©   (13.12.11 16:25) [34]
    > > Xmen  (13.12.2011 16:14:33)  [33]Нет файлы (оба) тоже
    > надо отправить на сервер

    Да уважаемый гуру я это понял, наверно сначала должен отправит контрольный файл а потом сам файл. Когда копирую с ФТП сначала идет сравнение а потом копирование и удаление контрольного файла или когда закачка на сервер файла закончена то удаляю контрольный файл.
  • Anatoly Podgoretsky © (13.12.11 16:48) [36]
    > Xmen  (13.12.2011 16:44:35)  [35]

    Конечно первым контрольный файл.
    Копирование идет всегда, иначе сравнение не возможно.
    На сервере файл не надо удалять.
  • Xmen (15.12.11 11:35) [37]
    Можете проверит сделал так.

    var dn, i, j:integer;
       F: TSearchRec;
       MyFile:TextFile;
       newFile, ftpFileName:string;
       ftpFileSize:Integer;
    begin
    LogFTP;//процедура соединение с сервером
    if FTPStatus=1 then
    if ListView3.Items.Count>0 then
      begin
        i:=0;
        ProgressBar2.Max:= ListView3.Items.Count-1;
        ProgressBar2.Min := 0;
        ProgressBar2.Position := 0;
        Memo1.Lines.Add('Открыт соединение с сервером');
        dn := FindFirst(path+'Send\*.*',faArchive,F);
        while dn = 0 do
          begin
            ProgressBar1.Position := 0;
            TotalBytes :=F.Size;
            newFile:=copy(f.Name,1,Length(f.Name)-4)+'.crc';
            AssignFile(MyFile,path+'Send\'+newFile);//создания файла проверки
            try
              Rewrite(MyFile);
              Write(MyFile,TotalBytes);
            finally
              CloseFile(MyFile);
              FTPClient.DataStream.LoadFromFile(path+'Send\'+newFile);
              FTPClient.StoreFile(ExtractFileName(FTPClient.GetCurrentDir+'Send/'+NewFile), false);
            end;
            FTPClient.DSock.OnStatus := SockPutCallBack;
            FTPClient.DataStream.LoadFromFile(path+'Send\'+f.Name);
            Memo1.Lines.Add('Отправка файла:   ' + f.Name+'      Размер:   ' + IntToStr(TotalBytes));
            if FTPClient.StoreFile(ExtractFileName(FTPClient.GetCurrentDir+'Send/'+f.Name), false) = true then
              begin
                FTPClient.List(FTPClient.GetCurrentDir+'/Send/',false);
                for j := 0 to FTPClient.FtpList.Count-1 do
                  begin
                   ftpFileName:= FTPClient.FtpList[j].FileName ;
                   ftpFileSize:= FTPClient.FileSize(FTPClient.GetCurrentDir+'Send/'+FTPClient.FtpList[j].FileName);;//если в сервер закачан файл и его размер подходит то ..
                   if (ftpFileName=f.Name) and (TotalBytes = ftpFileSize) then
                    begin
                      Memo1.Lines.Add('Загружен файл: '+F.Name+' время закачки: '+datetimetostr(NOW));
                      inc(i);
                      DeleteFile(path+'Send\'+f.Name);
                      DeleteFile(path+'Send\'+NewFile);
                      Break;
                    end;
                  end;
                ProgressBar1.Position := 0;
                Update;
              end
            else Memo1.lines.add('Ошибка отправки');
            ProgressBar2.Position := ProgressBar2.Position + 1;
            dn := FindNext(F);
          end;
        Memo1.Lines.Add('Успешно закачанных файлов: '+inttostr(i));
        Memo1.Lines.Add('Соединение закрыто');
        ProgressBar2.Position :=0;
      end;
    LogoutFTP;
    end;


    Это для отправки в сервер.
  • Anatoly Podgoretsky © (15.12.11 12:24) [38]
    > Xmen  (15.12.2011 11:35:37)  [37]

    > ftpFileSize:=
    > FTPClient.FileSize(FTPClient.GetCurrentDir+'Send/'+FTPClient.FtpList[j].FileName);;//если
    > в сервер закачан файл и его размер подходит то ..

    Это не гарантирует целостности файла
  • Xmen (15.12.11 13:24) [39]
    а как нужно тогда правильно сделать
  • Anatoly Podgoretsky © (15.12.11 14:27) [40]
    > Xmen  (15.12.2011 13:24:39)  [39]

    Как сказано, создавать файл с контрольной суммой, Свму сумму можно в
    название включить. В качестве КС лучше использовать хеш 64, будет более
    стандартно
  • Xmen (16.12.11 08:17) [41]
    function GetCheckSum(FileName: string): DWORD;
    var
     F: file of DWORD;
     P: Pointer;
     Fsize: DWORD;
     Buffer: array[0..500] of DWORD;
    begin
     FileMode := 0;
     AssignFile(F, FileName);
     Reset(F);
     Seek(F, FileSize(F) div 2);
     Fsize := FileSize(F) - 1 - FilePos(F);
     if Fsize > 500 then
       Fsize := 500;
     BlockRead(F, Buffer, Fsize);
     Close(F);
     P := @Buffer;
     asm
        xor eax, eax
        xor ecx, ecx
        mov edi , p
        @again:
          add eax, [edi + 4*ecx]
          inc ecx
          cmp ecx, fsize
        jl @again
        mov @result, eax
     end;
    end;

    Использовал так:
    ShowMessage(IntToStr(GetCheckSum(path+'Send\'+f.Name)));

    а как его в название включит ?
    у меня все файлы в формате 8.3.
    про хеш 64 инфы не нашел
  • Xmen (16.12.11 10:03) [42]
    почитал.
    http://www.delphimaster.net/view/15-1195018398/all
    >>Свму сумму можно в название включить.
    в название не могу написать потому что у меня название файла это шаблон
    например (ФФФФрнф.ффф
    ФФФФ - филиал получатель
    ф.ффф - филиал отправитель
    р - номер рейса (номер отправленного файла 0-9 a-z)
    н - номер дня (0-9 a-r)
  • Anatoly Podgoretsky © (16.12.11 10:41) [43]
    > Xmen  (16.12.2011 10:03:42)  [42]

    Не можешь, ни и не надо, придется считывать файлик.
    В FTP используется включения суммы в название, и ХЕШ в 64 байта, но это не
    важно, что бы с стандаром совпадало, главное, что бы свою роль выполняло и
    обнаруживало более одной ошибки передачи..
  • Xmen (16.12.11 10:52) [44]
    и забыл сказать у меня все файлы для отправки и приёма архивируется с помощью arj. Где то читал что есть у него свойство по работе с CRC. Можно как нибуд это использовать это в проге?
 
Конференция "Сети" » Отправка и приём файлов в FTP сервер [D7, WinXP]
Есть новые Нет новых   [119935   +162][b:0][p:0.005]