FAQ DelphiConsultez toutes les FAQ
Nombre d'auteurs : 124, nombre de questions : 934, dernière mise à jour : 23 octobre 2024 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums Delphi et Delphi et bases de données de www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose soient correctes. Les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous souhaitez y apporter des corrections ou la compléter, contactez un responsable (lien au bas de cette page).
Nous espérons que cette FAQ saura répondre à vos attentes. Nous vous en souhaitons une bonne lecture.
L'équipe Delphi de Developpez.com.
- Comment tester si un fichier existe sur un serveur FTP ?
- Comment tester si un dossier existe sur un serveur FTP ?
- Comment connaître facilement le contenu d'un dossier FTP sans analyse ?
- Comment modifier les droits d'un fichier avec IdFtp ?
- Comment construire un prototype fonctionnel de serveur FTP ?
- Comment créer une arborescence sur un serveur FTP ?
- Comment télécharger un fichier supérieur à 2 Giga-octets en FTP ?
- Comment obtenir la date de modification d'un fichier avec idFtp ?
- Comment mettre à jour la date de modification d'un fichier avec IdFtp ?
Il y a plusieurs manières de réaliser une sorte de Fileexists() sur FTP.
La première méthode est de tenter d'exécuter la commande Size sur le serveur. Normalement, tous les serveurs devraient supporter cette commande, qui sert à renvoyer la taille en octets d'un fichier. Si le fichier n'existe pas, une exception est levée, sinon, une variable booléenne est mise à true.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | function FTPFileExists(AFTPClient : TIdFTP; const AFile : string) : Boolean; begin Result := False; try if not AFTPClient.Connected then // Pas connecté ? AFTPClient.Connect(); // On connecte except Exit; // Impossible de connecter ! end; Result := AFTPClient.Size(APath)<>-1; end; |
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | procedure TForm1.Button1Click(Sender: TObject); begin IdFTP1.Host := 'ftp.foo.com'; IdFTP1.Username := 'anonymous'; IdFTP1.Password := 'anonymous@anonymous.com'; IdFTP1.Connect(); if FTPFileExists(IdFTP1,'/pub.txt') then MessageDlg('Le fichier existe !', mtInformation, [mbOK], 0) else MessageDlg('Le fichier n''existe pas.', mtInformation, [mbOK], 0); end; |
On procède ainsi : on tente de se positionner dans le répertoire passé en paramètre. Si celui-ci n'existe pas, une exception est levée, et on interrompt le fil d'exécution. Si le répertoire existe, on appelle List() en lui passant en paramètre une TStringList qui sera remplie avec le contenu du dossier. Le dernier paramètre de la fonction précise que nous ne voulons pas tout les détails (poids, date de modification) mais juste les noms.
L'existence du fichier est testée en cherchant (avec IndexOf()) le nom du fichier dans la liste. Le seul inconvénient de cette fonction est que si un dossier est nommé comme le fichier cherché, la fonction renverra aussi true.
Code Delphi : | Sélectionner tout |
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 | function FTPFileExists2(AFTPClient : TIdFTP; const ADirectory, AFile : string) : Boolean; var AOldDir : string; FolderList : TStringList; begin Result := False; try if not AFTPClient.Connected then // Pas connecté ? AFTPClient.Connect(); // On connecte except Exit; // Impossible de connecter ! end; try FolderList := TStringList.Create; AOldDir := AFTPClient.RetrieveCurrentDir; // Sauvegarder le répertoire actuel try AFTPClient.ChangeDir(ADirectory); // Si le dossier n'existe pas -> exception levée try AFTPClient.List(FolderList,'',False); // Lister les fichiers finally Result := FolderList.IndexOf(AFile) > 0; end; except end; finally AFTPClient.ChangeDir(AOldDir); // Revient à l'ancien dossier FolderList.Free; // Libère la StringList end; end; |
Code Delphi : | Sélectionner tout |
if FTPFileExists2(IdFTP1,'/data', 'test.txt') then ...
Enfin, vous pouvez aussi utiliser la liste parsée DirectoryListing après un appel à List(). La méthode est sensiblement égale à celle énoncée ci-dessus.
Il peut arriver que vous ayez besoin d'une fonction testant si un dossier existe sur un serveur FTP : une sorte de DirectoryExists() fonctionnant sur le serveur.
La méthode à suivre est la suivante : avec un TIdFTP, se connecter au serveur, et tenter de se placer dans le répertoire dont l'existence est à tester. Si ce répertoire n'existe pas, une exception sera soulevée par Indy, dans le cas contraire rien ne se passera. On utilisera ce comportement pour mettre un variable booléenne à true si l'exception n'est pas levée.
Dans la fonction suivante, on suit cette logique en mémorisant le répertoire courant, tenter de changer de répertoire, et rétablissant l'ancien répertoire si le changement a pu se faire :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | function FTPDirectoryExists(AFTPClient : TIdFTP; const APath : string) : Boolean; var AOldDir : string; begin Result := False; try if not AFTPClient.Connected then // Pas connecté ? AFTPClient.Connect(); // On connecte except Exit; // Impossible de connecter ! end; try AOldDir := AFTPClient.RetrieveCurrentDir; try AFTPClient.ChangeDir(APath); // Si le dossier n'existe pas -> exception levée Result := True; // Si on arrive ici -> OK except Result := False; end; finally AFTPClient.ChangeDir(AOldDir); // Revient à l'ancien dossier end; end; |
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | procedure TForm1.Button1Click(Sender: TObject); begin IdFTP1.Host := 'ftp.foo.com'; IdFTP1.Username := 'anonymous'; IdFTP1.Password := 'anonymous@anonymous.com'; IdFTP1.Connect(); if FTPDirectoryExists(IdFTP1,'/test') then MessageDlg('Le dossier existe !', mtInformation, [mbOK], 0) else MessageDlg('Le dossier n''existe pas.', mtInformation, [mbOK], 0); end; |
Indy 9 permet de récupérer dans une variable de type TCollection le contenu d'un dossier. Chaque item de la collection est relatif à un fichier et contient entre autres :
- Le type de l'élément (ItemType, qui vaut ditDirectory pour un dossier, ditFile pour un fichier, et ditSymbolicLink pour un lien symbolique)
- La taille de l'élement (Size)
- Le nom du fichier (FileName)
- La date de modification (ModifiedDate)
- Les permissions du groupe (GroupPermissions)
- Les permissions de l'utilisateur (UserPermissions)
- Le propriétaire (OwnerName)
Cette collection est située dans TIdFTP.DirectoryListing. Elle est remplie lors d'un appel à la méthode List(). Le texte brut renvoyé par le serveur est analysé (parsé) et les items sont ajoutés à la collection.
Précisions importantes à propos de cette propriété :
- Les parseurs de Indy 9 sont basiques : il ne supportent que les serveurs MS-DOS ou Unix. Cependant, beaucoup de serveurs émulent le formatage Unix, comme les serveurs Macintosh et la plupart des serveurs FTP Windows distribués en freeware et shareware. La version 10 permettra l'analyse des réponses des serveurs Bull, Cisco, IBM, etc. Aussi, si vous avez besoin de parseurs sophistiqués, vous devrez certainement installer la version 10.
- Certaines informations doivent être utilisées avec prudence : Ainsi la propriété Size contient une taille relative sous certains systèmes à des blocs d'enregistrements et pas à des octets. Utilisez plutôt la commande Size() du TidFTP.
- Il vaut mieux utiliser la commande MDTM (Modification Time) que la propriété ModifiedDateTime. Cette commande fait partie des extensions au protocole FTP définies. Cette fonction n'est pas directement implémentée dans Indy 9, mais vous pouvez le faire vous-même. Elle est par contre implémentée par défaut dans Indy 10.
Exemple permettant de rechercher un fichier dans un répertoire passé en paramètre :
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 | List(nil); for i:=0 to Pred(DirectoryListing.Count) do if (DirectoryListing[i].FileName=FName) and (DirectoryListing[i].ItemType=ditFile) then begin Result := True; Exit; end; |
Pour modifier les droits d'un fichier sur un serveur FTP il faut utiliser la commande SITE CHMOD <droits> <nomfichier>. Avec les composants Indy il faut utiliser la méthode Site :
Code Delphi : | Sélectionner tout |
idFTP.Site('chmod 666 MonFichier');
Cette fonction déclenche toujours une exception même en cas de succès. Il convient donc de la mettre dans une clause try except dans tous les cas.
Pour plus d'informations sur le sujet consultez le tutoriel indiqué dans la section Liens.
Pour créer une arborescence sur un serveur FTP et ainsi pouvoir y déposer un fichier sans avoir à vérifier l'existence de chaque répertoire, utiliser la procédure suivante :
Code Delphi : | Sélectionner tout |
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 | // Vérifie que le répertoire existe, créé l'arborescence si nécessaire procedure TForm1.ForceFtpDirectories(pathToForce: string); var FtpDirtoCreate : string; i : Integer; begin try IdFTP1.ChangeDir(pathToForce); // Le répertoire existe -> c'est fini! except // Le répertoire n'existe pas -> on vérifie et crée toute l'arborescence FtpDirToCreate:= '/'; // On commence par la racine du ftp repeat // On prend le prochain répertoire dans l'arborescence for i:= Length(FtpDirToCreate)+1 to Length(pathToForce) do begin if pathToForce[i]='/' then begin FtpDirToCreate:= LeftStr(pathToForce, i); break; end; //if end; //for i try IdFTP1.ChangeDir(FtpDirToCreate); // Le répertoire existe -> ok except // Le répertoire n'existe pas -> on le créé IdFTP1.MakeDir(FtpDirToCreate); end; //except // Et on passe au suivant tant que toute l'arborescence n'est pas vérifiée until FtpDirtoCreate=pathToForce; end; //except end; |
Je veux déposer un fichier 'toto.bin' dans le répertoire '/pub/driver/v2/releases/' d'un serveur FTP.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | procedure deposeFichier(); var IdFTP1 : TIdFTP; begin // On créé un objet TIdFTP IdFTP1:= TIdFTP.Create; // On renseigne les champs de connexion IdFTP1.Host:= 'nom_du_serveur'; IdFTP1.Username:= 'nom_utilisateur'; IdFTP1.Password:= 'mot_de_passe'; // Connexion au ftp IdFTP1.Connect; try // Vérification de l'existence du répertoire... //... Et création arborescence si nécessaire ForceFTPDirectories('/pub/driver/v2/releases/'); // Dépôt du fichier IdFTP1.Put('C:\toto.bin', '/pub/driver/v2/releases/toto.bin'); finally // Déconnexion quoi qu'il arrive IdFTP1.Disconnect; end; end; |
Avec les composants Indy ? Non... TIdFTP est limité à 2 Giga-octets du fait qu'un entier de type integer est utilisé en interne pour comptabiliser le nombre d'octets reçus (valeur maxi d'un integer = 2 147 483 647, d'où la limite de 2 147 483 647 octets = 2 Go).
Voici la fonction proposée qui porte la limite de téléchargement à 4 Giga-octets (et même beaucoup plus, mais cela n'a pas encore été testé aujourd'hui) :
Code Delphi : | Sélectionner tout |
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 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | uses Wininet; function FtpDownloadFile(strHost, strUser, strPwd: string; Port: Integer; ftpDir, ftpFile, TargetFile: string; ProxyUser,ProxyPassword:string; ALabel:TLabel=nil;AProgressBar: TProgressBar=nil): Boolean; function FmtFileSize(Size: Int64): string; begin if Size >= $E8D4A51000 then Result := Format('%.2f', [Size / $3B9ACA00]) + ' To' else if Size >= $3B9ACA00 then Result := Format('%.2f', [Size / $3B9ACA00]) + ' Go' else if Size >= $F4240 then Result := Format('%.2f', [Size / $F4240]) + ' Mo' else if Size < 1000 then Result := IntToStr(Size) + ' bytes' else Result := Format('%.2f', [Size / 1000]) + ' Ko'; end; const READ_BUFFERSIZE = 4096; // ou 256, 512, ... var hNet, hFTP, hFile: HINTERNET; buffer: array[0..READ_BUFFERSIZE - 1] of Char; bufsize, dwBytesRead: DWORD; fileSize:Int64; sRec: TWin32FindData; strStatus: string; LocalFile: file; bSuccess: Boolean; PC:integer; //Pourcentage de téléchargement UnFichier:TFileStream; begin Result := False; { Ouvre une session internet } hNet := InternetOpen('Nom du programme', // Agent INTERNET_OPEN_TYPE_PRECONFIG, // AccessType PChar(ProxyUser), // Nom utilisateur pour le Proxy PChar(ProxyPassword), // Mot de passe Proxy 0); // ou INTERNET_FLAG_ASYNC / INTERNET_FLAG_OFFLINE { l'agent contient le nom de l'application ou de l'entité appelant les fonctions Internet } { Le Handle de connexion est-il valide?} if hNet = nil then begin ShowMessage('Impossible d''accéder à WinInet.Dll'); Exit; end; {Connexion au serveur FTP} hFTP := InternetConnect(hNet, // Handle de InternetOpen PChar(strHost), // serveur FTP port,//ou bien (INTERNET_DEFAULT_FTP_PORT), PChar(StrUser), // username PChar(strPwd), // password INTERNET_SERVICE_FTP, // FTP, HTTP, ou Gopher? INTERNET_FLAG_PASSIVE, // flag: 0 ou INTERNET_FLAG_PASSIVE 0);// Nombre défini par l'utilisateur pour un callback if hFTP = nil then begin InternetCloseHandle(hNet); ShowMessage(Format('L''hôte "%s" n''est pas disponible',[strHost])); Exit; end; { Changer de répertoire } bSuccess := FtpSetCurrentDirectory(hFTP, PChar(ftpDir)); if not bSuccess then begin InternetCloseHandle(hFTP); InternetCloseHandle(hNet); ShowMessage(Format('Ne peut accéder au répertoire %s.',[ftpDir])); Exit; end; { Lecture de la taille du fichier } if FtpFindFirstFile(hFTP, PChar(ftpFile), sRec, 0, 0) <> nil then begin fileSize := sRec.nFileSizeLow; end else begin InternetCloseHandle(hFTP); InternetCloseHandle(hNet); ShowMessage(Format('Cannot find file ',[ftpFile])); Exit; end; { Ouvre le fichier } hFile := FtpOpenFile(hFTP, // Handle d'une session ftp PChar(ftpFile), // Nom du fichier GENERIC_READ, // dwAccess FTP_TRANSFER_TYPE_BINARY, // dwFlags 0); // Ceci est le contexte utiliser pour les Callback. if hFile = nil then begin InternetCloseHandle(hFTP); InternetCloseHandle(hNet); Exit; end; { Créer un nouveau fichier local } if FileExists(TargetFile) then DeleteFile(TargetFile); UnFichier:=TFileStream.Create(TargetFile,fmCreate); try dwBytesRead := 0; bufsize := READ_BUFFERSIZE; while (bufsize > 0) do begin Application.ProcessMessages; if not InternetReadFile(hFile, @buffer, // addresse d'un buffer qui reçoit les données READ_BUFFERSIZE, // Nombre d'octets à lire et à placer dans le buffer bufsize) // Nombre d'octets effectivement lus then Break; //On a fini de recevoir quelque chose if (bufsize > 0) and (bufsize <= READ_BUFFERSIZE) then bufsize:=UnFichier.Write(buffer, bufsize); dwBytesRead := dwBytesRead + bufsize; { Montrer Progression } PC:=Round(dwBytesRead * 100 / fileSize); if Assigned(AProgressBar) then AProgressBar.Position :=PC; if Assigned(ALabel) then ALabel.Caption := Format('%s of %s / %d %%',[FmtFileSize(dwBytesRead),FmtFileSize(fileSize) ,PC]); end; Result := True; finally UnFichier.Free; InternetCloseHandle(hFile); InternetCloseHandle(hFTP); InternetCloseHandle(hNet); end; end; |
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | procedure TForm1.Button1Click(Sender: TObject); var TargetFile:string; begin TargetFile := ExtractFilePath(Application.ExeName)+'fftw-3.1.2-dll.zip'; FtpDownloadFile('ftp.fftw.org','','', //Serveur ftp / Nom d'utilisateur sur le ftp / Mot de passe sur le ftp 21,'/pub/fftw','fftw-3.1.2-dll.zip', //Numéro de port FTP/ répertoire dans lequel se trouve le fichier / le fichier à télécharger TargetFile, //La destination du fichier '','', //Nom d'utilisateur et mot de passe Proxy éventuel Label1,ProgressBar1); //Un Label et une ProgressBar (facultatifs) ShowMessage('Téléchargement terminé'); end; |
- prise en compte des paramètres de connexion proxy (si vous en avez un)
- prise en compte des connexions ftp anonymes ou non
- La possibilité de mettre ou non en paramètre un TLabel informatif ou une TProgressBar, tous deux dédiés à l'affichage de la progression.
- La possibilité théorique de télécharger des fichiers de 2^63-1 octets (limite de Int64), limité toutefois au format de fichier (NTFS, FAT32) de votre disque dur.
L'une des solutions est d'envoyer une commande LIST et de tester les fichiers reçus. Cette méthode va retourner beaucoup d'informations pour pas grand chose au final. Pour obtenir la date de dernière modification d'un fichier on peut utiliser la commande ftp MDTM.
Cette commande a le format suivant :
Code : | Sélectionner tout |
MDTM NomFichier
Code : | Sélectionner tout |
213 DateFichier
La commande MTDM n'est pas implémentée dans IdFTP mais peut être envoyée avec la méthode SendCmd de TIdFTP.
Code Delphi : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | Function FtpGetDate(idFtp:TIdFtp;Const NomFichier:String):TDateTime; Var StDate: String; Y,M,D,H,N,S:Integer; Begin IdFTP.SendCmd('MDTM '+NomFichier,[213]); StDate := IdFTP.LastCmdResult.Text.Text; Y := StrToIntDef(Copy(StDate, 1,4),0); M := StrToIntDef(Copy(StDate, 5,2),0); D := StrToIntDef(Copy(StDate, 7,2),0); H := StrToIntDef(Copy(StDate, 9,2),0); N := StrToIntDef(Copy(StDate,11,2),0); S := StrToIntDef(Copy(StDate,13,2),0); Result := EncodeDate(Y,M,D)+EncodeTime(H,N,S,0); End; |
La date indiquée lors d'un upload en ftp est la date de l'upload et non pas la date du fichier. Si l'on veut garder la vraie date du fichier, il faut ensuite exécuter la commande MDTM sur le fichier venant d'être uploadé.
Le format de cette commande est le suivant :
Code : | Sélectionner tout |
MDTM DateFichier NomFichier
Cette commande n'est pas implémentée dans idFtp, par contre elle peut être envoyée directement en utilisant la méthode SendCmd de l'objet idFtp.
Code Delphi : | Sélectionner tout |
1 2 3 4 | Procedure FtpSetDate(Const NomFichier: String; LaDate: TDateTime); Begin idFtp.SendCmd('MDTM ' + FormatDateTime('YYYYMMDDHHNNSS', LaDate) + ' ' + NomFichier, [200, 250]); End; |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.