Upload des fichiers vers le serveur FTP avec Java

Pour écrire un code Java qui fait l'envoi des fichiers (upload) à partir du disque local vers le serveur FTP en ligne, l'API Apache Commons Net est un très bon choix pour les développeurs Java. Elle est simple et rend la programmation avec le FTP facile.

1- Télécharger l'API Apache Commons Net

Avant de commencer, il faut télécharger l'API Apache Commons Net qui contient un ensemble des outils réseaux et supporte plusieurs protocoles comme: FTP, Telnet, SMTP... Après le téléchargement, le fichier .jar doit être intégré dans la classpath de votre projet.

2- L'API Apache Commons Net pour le transfert des fichier via le protocole FTP

La classe FTPClient fournit des méthodes pour transférer un fichier local vers le serveur en ligne via le protocole FTP:
  • boolean storeFile(String remote, InputStream local)
  • OutputStream storeFileStream(String remote)
  • boolean storeUniqueFile(InputStream local)
  • boolean storeUniqueFile(String remote, InputStream local)
  • OutputStream storeUniqueFileStream()
  • OutputStream storeUniqueFileStream(String remote)
Quelle est la différence entre ces méthodes ? Et bien! Elles peuvent être classées comme suit:
  • Stocker les fichier en donnant un InputStream du fichier local (ceux sont les méthodes qui ont un InputStream comme paramètre). Ce type de méthodes est adopté quand on a pas besoin de connaitre comment les octets sont transférés à partir du fichier local au serveur. On laisse le système de faire ce traitement.
  • Stocker les fichier en écrivant vers le OutputStream de la connexion (ceux sont les méthodes qui ont un OutputStream comme sortie). Ce type de méthodes est nécessaire quand on veut contrôler la manière dont les octets sont transférés, en écrivant notre propre code pour lire les bytes via le fichier local qui seront sauvegarder dans le chemin du fichier distant à travers l'objet OutputStream. Cela peut être utile si on veut montrer la progression de l'upload, en calculant combien d'octets sont transférés sur la taille du fichier .
Les deux méthodes ci-dessus peuvent être utilisées en combinaison avec:
  • Nommer le fichier distant clairement (Ces méthodes qui acceptent un paramètre String nommé remote).
  • Laisser le les noms du serveur et le fichier distant avec un nom unique (Ces méthodes qui n'ont pas un paramètre String).
En dépit de la complexité de ces méthodes, seulement deux méthodes sont principalement utilisées dans la pratique:
  • boolean storeFile(String remote,InputStream local)
  • OutputStream storeFileStream(String remote)
En dehors de ces six méthodes, il y a aussi deux autres qui ont besoin d’être appeler avant et après le transfert du fichier:
  • boolean setFileType(int fileType): détermine le type du fichier, soit FTP.ASCII_FILE_TYPE ou FTP.BINARY_FILE_TYPE, est utilisée pour transférer le fichier. Le type par défaut est ASCII ( plain text ), mais il doit être mis en binaire dans le but qu'il marche pour tous les fichiers. Cette méthode doit être appelée avant que le transfert du fichier commence.
  •  boolean completePendingCommand(): Cette méthode doit être appelée après la fin du transfert pour compléter la transaction. Elle retourne true si le transfert est terminé avec succès, sinon false. On doit vérifier la valeur de retour de cette méthode pour s'assurer que l'upload a bien eu lieu.
    Par défaut, le protocole FTP établit la connexion en ouvrant un port pour le client et autorise le serveur à se connecter à ce port. C'est le mode active, mais il est parfois bloqué par le firewall et le transfert du fichier ne marche pas. Heureusement, le protocole FTP a un autre mode qui est le mode passive dont lequel la connexion est établie, en ouvrant un port dans le serveur pour que le client se connecte. Ce mode n'est pas bloqué par le firewall.

    Donc il est recommandé de s'orienter vers le mode passive avant le début du transfert des données avec l'appel de la méthode de la classe FTPClient enterLocalPassiveMode().

    3- Les étapes pour transférer un fichier en Java

    Pour bien écrire le code pour transférer un fichier vers le serveur FTP en utilisant l'API Apache Commons Net, les étapes suivants doivent être respectées:
    • Connecter et s'identifier au serveur.
    • Utiliser le mode passive pour la connexion.
    • Modifier le type du fichier à transférer en binaire.
    • Créer un InputStream pour le fichier local.
    • Appeler l'une des méthodes store...() pour commencer le transfert du fichier. Il y a deux scénarios:
      • En utilisant un InputStream: C'est la façon la plus simple puisque on laisse le système s'occuper de l'envoi et la réception. Il n y'a aucun code additionnel, juste faire passer l'objet InputStream dans la méthode correspondante, comme la méthode storeFile(String remote, InputStream local).
      • En utilisant OutputStream: cela est plus complexe, mais on gagne plus de contrôle sur les données transférées. En général, on doit écrire quelques lignes de code pour lire les octets à partir de InputStream du fichier local et écrire ces octets dans un OutputStream qui est retourné par la méthode store...(), tel que la méthode storeFileStream(String remote).
    • Fermer les flux de données InputStream et OutputStream.
    • Appeler la méthode completePendingCommand() pour accomplir la transaction.
    • Déconnecter du serveur.
    On doit vérifier la valeur du retour des méthode store...() et completePendingCommand() pour assurer que l'upload a été bien terminé.

    4- Programme de l'upload FTP en Java

    Ce code montre comment envoyer des fichier de la machine vers le serveur FTP en utilisant ces deux méthodes:
    • boolean storeFile(String remote, InputStream local)
    • OutputStream storeFileStream(String remote)
    Après l'appel de la méthode storeFile(), il n'est pas obligatoire d'appeler la méthode completePendingCommand(). Voici le code complet:

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import org.apache.commons.net.ftp.FTP;
    import org.apache.commons.net.ftp.FTPClient;

    public class FTPUploadFile {

    public static void main(String[] args) {
    String serveur = "adresseDuServeur";
    int port = 21;
    String user = "nomUtilisateur";
    String password = "votreMotdePasse";

    FTPClient ftpClient = new FTPClient();
    try {

    ftpClient.connect(serveur, port);
    ftpClient.login(user, password );
    ftpClient.enterLocalPassiveMode();

    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

    // Approche 1: upload d'un fichier en utilisant InputStream
    File file = new File("C:/plugins et styles.txt");

    String chemin = "plugins et styles.txt";
    InputStream inputStream = new FileInputStream(file);

    System.out.println("Début de l'upload");
    //résultat de l'upload
    boolean res = ftpClient.storeFile(chemin, inputStream);
    //fermet le flut de lecture
    inputStream.close();

    if (res==true) {
    System.out.println("Le fichier "+chemin+" a été transféré avec succès");
    }

    // Approche 2: upload d'un fichier en utilisant OutputStream
    file = new File("C:/piste 1.wma");
    chemin = "audio/piste 1.wma";
    inputStream = new FileInputStream(file);

    System.out.println("Début de l'upload");
    OutputStream outputStream = ftpClient.storeFileStream(chemin);
    byte[] bytesIn = new byte[4096];
    int buffer = 0;

    //tant qu'on a pas atteint la fin du fichier
    System.out.println("Transfert en cours...");
    int transferé = 0;
    int pourcentage = 0;
    //tant qu'on a pas atteint la fin du fichier
    while ((buffer = inputStream.read(bytesIn)) != -1) {
    //lire les données avec un buffer de 4096 octets
    outputStream.write(bytesIn, 0, buffer);
    transferé += buffer;
    pourcentage = (int) (transferé*100/file.length());
    System.out.println(pourcentage+"%");
    }
    //fermer les flux de lecture de d'écriture
    inputStream.close();
    outputStream.close();

    //résultat de l'upload
    res = ftpClient.completePendingCommand();
    if (res) {
    System.out.println("Le fichier "+chemin+" a été transféré avec succès");
    }

    } catch (IOException e) {
    System.out.println(e.getMessage());
    e.printStackTrace();
    } finally {
    try {
    if (ftpClient.isConnected()) {
    //fermer la connexion FTP
    ftpClient.logout();
    ftpClient.disconnect();
    }
    } catch (IOException ex) {
    ex.printStackTrace();
    }
    }
    }
    }
    L'exécution de ce code retourne que le transfert a été bien accompli:

    Début de l'upload
    Le fichier plugins et styles.txt a été transféré avec succès
    Début de l'upload
    1%
    2%
    3%
    .
    .
    97%
    98%
    98%
    99%
    99%
    100%
    Le fichier piste 1.wma a été transféré avec succès