Android: not downloading all files from an FTP server when using Indy TIdFTP component

111 views Asked by At

I have implemented the following code to download files from an FTP server that are inside folders and subfolders.

void TFAct::Download()
{
  try
  {
    Ftp->ChangeDir("/");
    //Actualizo//
    NewDats(CTemp);
  }
  catch (...)
  {
  }
}

void TTFAct::::NewDats(AnsiString Path)
{
  std::auto_ptr<TStringList> Elementos (new TStringList);
  Ftp->List(Elementos.get());
  int NumElemnt = Ftp->DirectoryListing->Count;
  int Pos;
  bool *IsDir = new  bool[NumElemnt];
    
  for (int i=0;i<NumElemnt;i++)
  {
    TIdFTPListItem*  ListItem = Ftp->DirectoryListing->Items[i];
    Elementos->Strings[i] = ListItem->FileName;
    FechAlla[i] = ListItem->ModifiedDate;
    IsDir[i]=ListItem->ItemType == ditDirectory;
  }
    
  for (int i=0;i<NumElemnt;i++)
  {
    //Si es una SubCarpeta
    if(IsDir[i])
    {
      Ruta = Path + Elementos->Strings[i];
      AnsiString Copia = Path + Elementos->Strings[i];
      Folder = Ruta.SubString(Ruta.LastDelimiter("\")+1,Ruta.Length());
    
      //Compruebo si el Directorio existe
      if(DirectoryExists(Ruta))
      {
        Ftp->ChangeDir(Elementos->Strings[i]);
        NewDats(Ruta + "/");
      }
      else
      {
        CreateDir(Ruta);
        Ftp->ChangeDir(Elementos->Strings[i]);
        NewDats(Ruta + "/");
      }
    }
    else
    {
      try
      {
        Ftp->Get(Elementos->Strings[i],Copia,true); //bajo archivo
      }
      catch(...)
      {
      }
    } //IsDir
    
  }//for
    
  Ftp->ChangeDirUp();
}

On Windows, it works perfectly.

An Android, it goes through folders and subfolders perfectly, but when it has to download files, sometimes it downloads all of the files, other times it downloads only some of the file, and other times it downloads none at all.

What could be the problem?

1

There are 1 answers

3
Remy Lebeau On

I see a lot of issues with this code:

  • you should not be using AnsiString at all on Android (or Windows, for that matter). Use UnicodeString (or better, System::String) instead. Both Operating Systems are Unicode-based, and you are using a Unicode-based version of C++Builder, and a Unicode-based version of Indy, so don't use ANSI strings at all.

  • There is no point in passing a TStringList into TIdFTP::List() if you are going to ignore its output. So, you should pass in nullptr and just use TIdFTP::DirectoryListing by itself.

  • You are leaking your IsDir array. Use std::vector instead of new[].

  • When calling Ruta.LastDelimiter("\"), you need to escape the \ character using either "\\" or R"(\)". Or, you could simply use ExtractFileName() instead of using Ruta.SubString() at all. However, you are also mixing \ and / characters in your paths. Don't do that. Use / for FTP paths, and use System::Sysutils::PathDelim or System::Ioutils::TPath::DirectorySeparatorChar for local filesystem paths. Don't use a single string to represent both kinds of paths, keep them separate.

  • but most importantly, you are ignoring ALL possible errors. If Indy encounters an error, it will throw an exception, which you are catching and discarding. There are a number of reasons why an FTP server might reject access to a file/folder. Maybe you requested in invalid path. Maybe you don't have access to the path. Not only are you discarding all errors, but you are not even logging them anywhere, so you can't possibly know when an error has actually occurred, or what kind of error it was. Was it an ignorable error? Was it a fatal error? You don't know, so you aren't acting on it.