«

»

may 30 2012

Apache Commons FTP – Subiendo archivos a servidores

Últimamente estamos viendo diversos tutoriales de como consumir datos de una web o web service, en esta ocasión lo que vamos a plantear es la otra cara, subir archivos a un servidor.

Esta tarea que puede hacerse de muchas y diferentes maneras, en este tutorial vamos a hacerlo mediante FTP, de una forma práctica y realmente sencilla.

Lo primero que vamos a destacar es que nos apoyaremos en una de las joyitas que puede encontrarse por ahí a nivel de librerías, para esta ocasión usaremos la Apache Commons FTP.


 
Pues manos a la obra, en primer lugar descargaremos esta librería desde su web:
http://commons.apache.org/net/download_net.cgi
 

Una vez descargada incluiremos el archivo commons-net-3.0.1.jar en el buid path de nuestro proyecto. Cuando indicamos el nombre de este archivo es porque se trata de la versión actual, lógicamente añadiremos el archivo de la última versión.
Una vez este jar en nuestra carpeta /libs, y antes de que se nos pase, dotaremos a nuestro proyecto del único permiso que requiere este tutorial, en el manifest añadiremos el permiso de internet:

<uses-permission android:name="android.permission.INTERNET"/>

 
Importaremos a nuestra actividad lo necesario de esta librería

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;

 
Y empezaremos con el código. Para esta ocasión yo he añadido un botón que al ser pulsado llamara al método originalmente llamado “subirArchivo()” que dentro de una acción Try, instanciará el FTPClient, le pasará los datos de nuestro servidor e indicará que archivo de nuestro terminal queremos subir (y su ubicación), así como en que carpeta de nuestro servidor queremos guardarlo.

Realmente esto no tiene mucho misterio, ya que es el proceso que se sigue siempre que movemos o subimos algo a un servidor.
Vamos a ver el código comentado.
El listener del botón es ya conocido de todos, pero que no vaya a quedar por ponerlo :)

click.setOnClickListener(new View.OnClickListener(){
    public void onClick(View view){
        subirArchivo();
    }
});

 
Ahora llegamos a la parte interesante, el método que va a subir nuestro archivo al servidor, vamos a verlo comentado y después junto para que si queréis probarlo en algún proyecto vuestro no haya mas que copiarlo.

// Instanciamos FTPClient
FTPClient ftpClient = new FTPClient();

// Facilitamos la dirección del host al que vamos a subir nuestro archivo
ftpClient.connect(InetAddress.getByName("FTP.ejemplo.com"));

//Indicamos el usuario y contraseña del servidor, necesario para acceder
ftpClient.login("usuario", "contraseña");

 
Con esto ya hemos indicado a nuestro proyecto el servidor que vamos a utilizar y facilitado los datos para entrar.

Seguidamente indicaremos en que carpeta de nuestro servidor vamos a alojar el archivo que estamos subiendo y de que tipo es:

ftpClient.changeWorkingDirectory("/micarpeta");
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);

 
Otro dato no menos importante es, lógicamente, indicar que archivo de nuestro terminal o SD vamos a subir. Ojo, hay que especificar la ruta y el archivo, puntualizo porqué aunque puede pasar por una tontería, como se modifique uno de los parámetros y el otro no, podemos llevarnos un rato mirando a ver que pasa… Verídico ;)

buffIn=new BufferedInputStream(new FileInputStream("/sdcard/foto.jpg"));
ftpClient.storeFile("foto.jpg", buffIn);

 
Una vez hechas estas acciones, tenemos prácticamente todo lo necesario para que empiece a subir el archivo.
Cerraremos las conexiones, nos deslogueamos del servidor y nos desconectaremos del FTP.

buffIn.close();
ftpClient.logout();
ftpClient.disconnect();

 
Y realmente, poco más, como adelantábamos al principio, esta librería facilita bastante las cosas.

 
Aquí tenéis el código completo del método.

public void subirArchivo() throws SocketException, UnknownHostException, IOException {

    try {

        FTPClient ftpClient = new FTPClient();
        ftpClient.connect(InetAddress.getByName("FTP.ejemplo.com"));
        ftpClient.login("usuario", "contraseña");

        ftpClient.changeWorkingDirectory("/micarpeta");
        ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
        BufferedInputStream buffIn=null;
        buffIn=new BufferedInputStream(new FileInputStream("/sdcard/foto.jpg"));
        ftpClient.enterLocalPassiveMode();
        ftpClient.storeFile("foto.jpg", buffIn);

        buffIn.close();
        ftpClient.logout();
        ftpClient.disconnect();

    } catch (Exception e){
        Log.i("consola","Ups...");}
    }

}

 
Este tutorial es una base sobre la que empezar a trabajar, las posibilidades son muchas, ahora ya queda la cosa en adaptarlo y añadirle las cosas necesarias que requieran nuestro proyecto.
Con este sencillo ejemplo y un cliente ftp sencillo tipo FileZilla, pueden verse rápidmente los resultados.

 
 
Esperamos que haya sido de utilidad.
Saludos!
 

Acerca del autor

Vierco

Desarrollador de android, Responsable del proyecto "AndYou para android", llevando a cabo la startup "Hello Vierco". Me siento delante de un ordenador o móvil y se me pueden ir los días..

  • Javier Val

    Hola ¿qué tal? Estoy desarrollando una aplicación que se conecta a un servidor FTP (FileZilla), pero antes de poder subir o bajar archivos, quiero que la aplicación valide el nombre y la contraseña del usuario. Alguna idea de cómo tiene que ser el código?

    Saludos
    Javier

    • Naroh

      Con el metodo de login de FTPClient validas el usuario y el pasw.

      Saludos!

  • fran

    hola vierco, muchas gracias por el ejemplo.

    Me gustaría saber si hay algún sitio del que descargarse el proyecto completo para poder importarlo en eclipse y probarlo.

    Utilizo eclipse índigo (versión 3.7.2) en ubuntu 12.04, ¿donde tendría que añadir el fichero commons-net-3.0.1.jar? ¿sería en /usr/lib/eclipse/plugins?

    Saludos, fran

  • Lalo De Santiago

    Buen día disculpa en la parte donde dice “Log.i(“consola”,”Ups…”)”, no crees que hace falta terminar la instrucción?????? y pues como es así cual es la parte de código que hace falta????????, de antemano gracias.

  • Lalo De Santiago

    No sería mejor poner al final del catch un mensaje como por ejemlo de:
    System.out.println(e.getMessage());

    o

    System.out.println(“Consola, Ups!”);

    o

    System.out.println(“Something wrong happend”);

    digo pr que el catch en este caso se ocuparía de una condición de error, ya sea en el incorrecto login, server o el archivo en cuestión a subir, verdad??, bueno esto lo pongo como un pequeño ejemplo y tal vez recomendación para dicha condición del catch, bueno espero tu respuesta y gracias por la info.

  • Lalo De Santiago

    Y si el programa se hiciera sin necesidad de un botón que estuviera directo dentro de la clase principal y dentro del “public static void main(String[] args)” también llevaría los Exception vdd??, en este caso así lo estoy desarrollando pero me da un error de permision deneid, que crees que sea lo que está mal de antemano gracias y disculpa por tantas preguntas soy principiante en java y aún más en el uso de la librería commons net.

  • http://www.linkware.com.ve Rommel de Caracas

    hola Lalo de Santiago Valida si tienes agredado en el Manifiest la instruccion sigiuente , estoy probando el codigo a ver que tal, tambien necesito algo y al pacer esta libreria es una solucion que he visto en otros foros. por favor si tienen el proyecto creado no dejen de publicar el link. si yo lo pruebo les colocare esta publicacion.

  • http://www.linkware.com.ve Rommel de Caracas

    Hola Gente, aunque probe el codigo y agregue todos los import eclipse no encontro ningun error pero l ejecutarlo da error y se sale del sistema… alguien le ha funcionado ha visto

  • Arthur

    Hola a mi tampoco me funciona

    al compilar no me da ningun error

    pero una vez ejecutada la aplicacion en el simulador y “Unfortunately Programa has stopped”

    Porque ocurre eso???

  • JokinFQ

    EL MISMO ERROR QUE ARTHUR “Unfortunately Programa has stopped”
    COMO LO ARREGLAMOS?

    package com.prueba;
    import com.prueba.R;
    import android.os.Bundle;
    import android.app.Activity;
    import android.util.Log;
    import android.widget.TextView;
    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.net.*;
    import org.apache.commons.net.ftp.FTP;
    import org.apache.commons.net.ftp.FTPClient;

    public class MainActivity extends Activity {
    TextView txt0;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    txt0=(TextView)findViewById(R.id.txt0);

    }

    public void subirArchivo() throws SocketException, UnknownHostException, IOException {
    txt0.setText(“Subiendo Archivo…”);
    try {

    FTPClient ftpClient = new FTPClient();
    ftpClient.connect(InetAddress.getByName(“ftp.mihost.org”));
    ftpClient.login(“miuser”, “mipass”);

    // ftpClient.changeWorkingDirectory(“/micarpeta”);
    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    BufferedInputStream buffIn=null;
    buffIn=new BufferedInputStream(new FileInputStream(“/sdcard/archivo.txt”));
    ftpClient.enterLocalPassiveMode();
    ftpClient.storeFile(“archivo.txt”, buffIn);

    buffIn.close();
    ftpClient.logout();
    ftpClient.disconnect();

    } catch (Exception e){
    Log.i(“consola”,”Ups…”);}
    }

    }

  • http://www.hellovierco.com Vierco

    Hola,

    sin ver los Logs, entiendo que los tiros pueden ir acerca de que a partir de android 4.0 cualquier conexión se debe realizar de forma asíncrona para evitar problemas con el hilo principal de la aplicación.
    Este ejemplo realiza la conexión desde el hilo principal, por lo que si hace la conexión desde dentro de un AsynTask, por ejemplo, no debe de haber ningún inconveniente.

    Saludos.

  • arfs

    Hola vierco gracias por tu respuesta pero disculpa que no te haya entendido… podrias explicarlo un poco mas para novatos o como se hace un AsynTask?
    Supongo que sera envolver entre llaves pero ,,, eso podrias poner un ejemplo por favor?

  • utt

    PUEDE ALGUIEN ARROJAR LUZ SOBRE EL ASUNTOO??? yo tambien tengo el mismo problema

  • aas

    ESTO ES UNA MIERDA no funcionaaa !!!! vaya engaño!”

  • http://www.hellovierco.com Vierco

    Agradezco el interés y los comentarios indicados.
    He probado de nuevo la librería y no he tenido problema por lo que, esperando que os ayude, os paso un enlace donde podéis descargar un zip con el proyecto para que lo importéis a Eclipse y lo tengáis funcionando.
    En el código, donde figuran las XXXXXX deben ir los datos de vuestro FTP, las rutas y nombre del archivo a subir.

    arfs, en el ejemplo que os paso la conexión va dentro de un asyncTask, para que puedas ver como va. Es muy práctico y muy sencillo.

    Un saludo, Vierco.

    http://www.hellovierco.com/testing/pruebas.zip

  • elde antes

    Ese ahiiii aupa hiii !!! el puto amo!! jaja ke grandeee! mutxas graciass!! lo pruebo i komentoo!!! POR FIIIINNN

  • elde antes

    Hola he probado tu proyecto
    Y FUNCIONAA!!!

    AL QUEE NO LE FUNCIONE QUE REVISE SUS PATHS EN EL HOST
    GRACIASS!!!

    • SpeedrunAway

      Hola elde antes,

      a que te refieres con el “PATHS EN EL HOST” a la instalacion de java y sus variables de entorno sistema o usuario?

      Atento a tu repuesta

    • SpeedrunAway

      amigo bueno, comento que he configurado bien el JAVA_HOME, por lo que no he configuido hacerlo funcionar.

      despues de haber configurado los parametros del server ftp , usuario, directorio, etc le hago click en subir archivo y se cae la aplicacion y se cierra

      que crees que puediera estar pasando?

      por favor ayudame

  • Tipo

    Hola a mi me funciona pero no puedo subir archivos que estandentro de carpetas de programas como el watsapp … que permisos se requieren en el manifest?’
    gracias

  • elde antes

    HOLAAA

    en el simulador funcionaba bien pero en el mobil noo

    Pruebas se a interrumpido inesperadamente Intentalo de nuevo!

    y eso por otro lado en el simulador funciona perfecto…
    porque ocurre eso?

    como solucionarlo?

    gracias un saludo

  • elde antes otra vez

    POR FAVOR ayudenme con estoo!!!! soy incapaz de subir un archivo !!! PORQUE FUNCIONA EN EL SIMULADOR Y NO EN EL TELEFONO???

    • http://www.hellovierco.com Vierco

      Hola,

      se me ocurre al funcionarte en el emulador y no en el dispositivo que es posible que las rutas de la SD estén incorrectas o no sea exactas.
      revisa eso en primer lugar.

      Saludos

  • elde antes

    lo he comprobado y no consigo nada, probe con la ruta escrita de forma convencional

    “sdcard/at.txt”

    de esta manera tambien

    “/sdcard/at.txt”

    y con esto otro que eclipse sugiere

    FileInputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + “/at.txt”

    y con ninguno…

    a usted le funciona en el telefono’?

    No sera un tema de persmisos?
    x si las moscas implemente estas lineas pero tampoco

    un saludo

  • elde antes

    hay alguna otra manera de escribir ruttass== ??

  • Vierco

    Tienes puesto el permiso de internet?
    Prueba a descargar el proyecto ejemplo, este está testeado…
    Si persiste, pon los logs

    Saludos

  • Franco

    Hola! funciona perfectamente bien tu ejemplo. Es más, lo adapté a mis necesidades y sigue andando.
    Que pasa si en server existe un archivo con el mismo nombre que el que quiero subir.. Existe una método para validar esto…

    • Irving

      ¿Podrías compartir tu código?

  • Irving

    ¡Suban nuevamente el código por favor! La aplicación no corre en mi dispositivo.

  • Daniel Barahona

    Irving
    import org.apache.commons.net.ftp.FTP;
    import org.apache.commons.net.ftp.FTPClient;
    y recuerda que en la carpeta libs te debe aparecer el .jar
    y en el AndroidManifest poner

    Soy novato en todo esto, ahora quiero bajar un archivo desde ftp y después ejecutarlo para modificar la BD …
    //

    try {
    Log.i(“1″,”Ups…”);
    FTPClient ftpClient = new FTPClient();
    Log.i(“1.2″,”Ups…”);
    ftpClient.connect(InetAddress.getByName(“xxx.xxx.xxx.xxx”));//utilize direccion ip
    Log.i(“1.3″,”Ups…”);
    ftpClient.login(“user”, “password”);
    Log.i(“2″,”Ups…”);

    ftpClient.changeWorkingDirectory(“/Prueba2Serv”);
    ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
    BufferedInputStream buffIn=null;
    Log.i(“3″,”Ups…”);

    buffIn=new BufferedInputStream(new FileInputStream(“/data/data/com.example.login/files/prueba_int.txt”));
    ftpClient.enterLocalPassiveMode();
    // ftpClient.storeFile(a, buffIn);

    Log.i(“4″,”Ups…”);
    buffIn.close();
    ftpClient.logout();
    ftpClient.disconnect();
    // database.execSQL(“update venta set estado = 2″);
    Toast.makeText(getBaseContext(), “Datos Enviado Correctamente”, Toast.LENGTH_LONG).show();
    } catch (Exception e){

    Toast.makeText(getBaseContext(), “Problemas al enviar datos”+e.getMessage(), Toast.LENGTH_LONG).show();

    //Log.i(“consola”,”Ups…”+e.getMessage());
    }

    Atte Dabes

    • Irving

      Me marca un Error al correr el código. En la pantalla del Android dice: “Problemas al enviar datossocket failed: EACCES(Permission denied). ¿Podrías ayudarme?

  • Victor

    Funciona increiblemente bien en Android 2.3.3 Gingerbread, lo buscaba de hacia horas!!! gracias!

  • roland

    muchas gracias por la informacion. la voy a probar y hago comentarios, saludos

  • Rosendo

    ¿Y si el directorio al que quiero subir el archivo no existe? ¿Cómo puedo crear el directorio remotamente? ¿Sabroso tema no? ;)

    • Gyssa

      ¿Se crea en automático el directorio si no existe?

  • Manuel

    Buenas!

    Ante todo darte las gracias por tu código, pero tengo una duda, yo lo uso y aquí:

    // Instanciamos FTPClient
    FTPClient ftpClient = new FTPClient();
    // Facilitamos la dirección del host al que vamos a subir nuestro archivo
    ftpClient.connect(InetAddress.getByName(“FTP_NAME”));
    //Indicamos el usuario y contraseña del servidor, necesario para acceder
    ftpClient.login(“USER”, “PASS”);

    me produce un error y se me sale del try… no pasa de este punto, y los datos del ftp están correctos, podrías ayudarme?

    Un Saludo y Muchas Gracias.

  • Pablo

    Simplemente al instanciar FTPClient se cierra la aplicación

    Lamentablemente el link ya no funciona y no se por donde seguir.

    Tengo agragado al manifiesto el permiso de internet, y de la memoria externa

    Si alguien tuviera el proyecto funcionando o pudiera darme una mano estaría muy agradecido. lo estoy probando en Androdi v:2.3.4 GINGERBREAD.VJKPE

    Dejo mi código. así como esta al instanciár

    FTPClient ClienteFTP =new FTPClient();

    se MUERE!!

    —————————————————————————

    package enviosTrack.aplicacion.utilidades;

    import java.io.BufferedInputStream;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.net.SocketException;

    //import org.apache.commons.net.ftp.FTPClient;

    import org.apache.commons.net.ftp.FTP;
    import org.apache.commons.net.ftp.FTPClient;

    import android.widget.TextView;

    public class FtpCliente {

    private String prop_servidor;
    private Integer prop_puertoServidor=21;
    private String prop_usuarioFtp;
    private String prop_passFtp;
    private String prop_directorioServidor;
    private String prop_nombreArchivoServidor;
    private String prop_archivoLocal;

    TextView p_prueba;

    public FtpCliente(TextView prueba,String servidor, String usuario, String pass, String directorioServidor, String nombreArchivoServidor, String archivoLocal ) {

    p_prueba=prueba;

    prop_servidor=servidor;
    prop_usuarioFtp=usuario;
    prop_passFtp=pass;
    prop_directorioServidor=directorioServidor;
    prop_nombreArchivoServidor=nombreArchivoServidor;
    prop_archivoLocal=archivoLocal;

    this.SubirArchivo();

    }

    public Boolean SubirArchivo(){
    Boolean resultado=true;

    if(resultado)
    p_prueba.setText(“logeado”);
    else
    p_prueba.setText(“no logeado”);

    FTPClient ClienteFTP =new FTPClient();

    /*try {
    ClienteFTP.connect(prop_servidor, prop_puertoServidor);
    resultado=ClienteFTP.login(prop_usuarioFtp, prop_passFtp);

    ClienteFTP.changeWorkingDirectory(prop_directorioServidor);
    ClienteFTP.setFileType(FTP.TELNET_TEXT_FORMAT);
    BufferedInputStream buffIn=new BufferedInputStream(new FileInputStream(prop_archivoLocal));
    ClienteFTP.storeFile(prop_nombreArchivoServidor, buffIn);

    buffIn.close();
    ClienteFTP.logout();
    ClienteFTP.disconnect();

    } catch (SocketException e) {
    resultado=false;

    } catch (IOException e) {
    resultado=false;
    }*/

    return resultado;
    }

  • david

    cual es la ruta del código fuente amigo. xq este http://www.hellovierco.com/testing/pruebas.zip ya no esta disponible, de antemano gracias si se puede a mi correo te lo agradeceria dfs-fsd@hotmail.com

  • Haru

    Madre mía, me había mirado varios tutoriales y no entendía ni papa, y ha sido encontrar esto y tener el FTP subiendo en 5 minutos, muchísimas gracias!!! Sigue así!

  • https://plus.google.com/101795248076773389960 alan moreno

    tengo un problema, tengo un celular con android version 2.3, y otra con la 4.2.2, y es en esta version (4.2.2) que no coencta nada :(.

  • https://www.facebook.com/vichon.ramirez Vicente Ramirez Vergara

    me funciona todo ok ;) gracias!.. tengo una pregunta…. como se hace para el caso que quiera descargar una foto desde el servidor a mi celular?. Saludos

  • Gregorio

    para enviar toda una carpeta con archivos se haría de la misma manera?