Quien soy? RSS feed Enviar por email Imprimir Parar este menu Ir arriba
Blogzote.com
Mexico, informatica, internet, musica y algo mas…

Oracle UTL_FTP

Hace unos me surgió la necesidad de realizar el paso de algunos archivos planos entre servidores, el problema es que este paso se va a realizar constantemente, entonces tuve que pensar en una solución que fuera fácil, aparte esos archivos no son mas que información que se procesa e ingresa a una tabla de base de datos.

De entrada la solución que se proponía era realizar un shell script para realizar el paso de archivos vía ftp de un servidor a otro, soluciona el problema pero no estaba muy de acuerdo, primero tener que llamar a un shell para después conectarte a Oracle y llamar a un procedimiento, le quita el control a Oracle sobre el manejo de esos archivos, otra era usar directamente UTL_FILE, pero este paquete sirve para el manejo de archivos en el mismo servidor de base de datos, que yo sepa, con utl_file no se puede manejar archivos de otras maquinas.

Tiempo atrás ya había leído de la existencia de un paquete para el manejo de conexiones tcp, el paquete se llama UTL_TCP, suponía entonces que ya debería de existir algo relacionado con el manejo de archivos entre servidores, la opción lógica era buscar el paquete UTL_FTP pero sorpresa, este no existe, bueno y ¿que dice Google al respecto? le di buscar utl_ftp y me regreso varias paginas, me encontré primero con un script guardado en sourceforce llamado “plsqlftp“, pero no me convenció, su desarrollo se ve casi abandonado y no encontré un solo ejemplo de cómo se usa, acabe descartándolo.

Rascándole un poquito mas a los resultados me tope con el que finalmente implemente, le llamaron “FTP Interfase“, me quedo perfecto para lo que necesitaba, se ve bastante robusto y completo, yo solo use tres funciones, “VERIFY_SERVER”, “PUT” y “GET” pero tiene muchas mas, igual más adelante las pueda necesitar, aquí les dejo el procedimiento que generé para realizar los movimientos de archivos:

  --
  -- MOVE_FILE
  --
  -- move file "p_filename" with ftp interfase, use put or get "p_type_move
  -- "p_type_move" = "PUT" => from "p_localpath" to "p_remotepath"
  -- "p_type_move" = "GET" => from "p_remotepath" to "p_localpath"
  -- use ftp server "p_hostname" with usr "p_username" and pwd "p_password"
  --
  procedure move_file    (
     p_type_move           in      varchar2,
     p_localpath           in      varchar2,
     p_remotepath          in      varchar2,
     p_filename            in      varchar2,
     p_username            in      varchar2,
     p_password            in      varchar2,
     p_hostname            in      varchar2,
     p_error               out     varchar2) is

     v_exception    exception;
     p_status       varchar2(32000);
     p_bytes_trans  number;
     p_trans_start  date;
     p_trans_end    date;
     dummy          boolean;
  begin

     if (p_type_move != 'PUT') and
        (p_type_move != 'GET') then
        p_error := 'ERROR: value for p_type_move not supported.';
        raise v_exception;
     end if;

     dummy := ftp_interface.verify_server (
                    p_remotepath           => p_remotepath,
                    p_username             => p_username,
                    p_password             => p_password,
                    p_hostname             => p_hostname,
                    v_status               => p_status,
                    v_error_message        => p_error,
                    p_port                 => 21,
                    p_filetype             => 'ASCII',
                    p_mainframe_connection => FALSE );

     if p_status != 'SUCCESS' then
        raise v_exception;
     end if;

	 if p_type_move = 'PUT' then

	     dummy := ftp_interface.put (
                    p_localpath            => p_localpath,
                    p_filename             => p_filename,
                    p_remotepath           => p_remotepath,
                    p_username             => p_username,
                    p_password             => p_password,
                    p_hostname             => p_hostname,
                    v_status               => p_status,
                    v_error_message        => p_error,
                    n_bytes_transmitted    => p_bytes_trans,
                    d_trans_start          => p_trans_start,
                    d_trans_end            => p_trans_end,
                    p_port                 => 21,
                    p_filetype             => 'ASCII',
                    p_mainframe_ftp        => FALSE,
                    p_mainframe_cmd        => '' );

         if p_status != 'SUCCESS' then
            raise v_exception;
         end if;

     elsif p_type_move = 'GET' then

		 dummy := ftp_interface.get (
                    p_localpath            => p_localpath,
                    p_filename             => p_filename,
                    p_remotepath           => p_remotepath,
                    p_username             => p_username,
                    p_password             => p_password,
                    p_hostname             => p_hostname,
                    v_status               => p_status,
                    v_error_message        => p_error,
                    n_bytes_transmitted    => p_bytes_trans,
                    d_trans_start          => p_trans_start,
                    d_trans_end            => p_trans_end,
                    p_port                 => 21,
                    p_filetype             => 'ASCII',
                    p_mainframe_ftp        => FALSE,
                    p_mainframe_cmd        => '' );

         if p_status != 'SUCCESS' then
            raise v_exception;
         end if;

     end if;

     p_error := 'OK';

  exception
     when v_exception then
         null;
     when others then
         p_error := 'ERROR: ' || SQLERRM;
  end move_file;

La llamada al procedimiento se realiza de manera muy fácil:

move_file('GET',
          '/datos',
          '/home',
          'test.txt',
          'usuario',
          'password',
          'ip_del_host',
          v_error);

28 comentarios para “Oracle UTL_FTP”

  1. vane
    Julio 28th, 2007 | 22:09

    hola muy bueno el articulo, mencionaste el utl_file y yo estoy tratando de armar un excel a partir de una consulta en oracle ej:

    select * from tabla
    where nombre = ‘jose’;

    esta consulta da varios registros como resultados y el excel tendria que quedar asi:

    Nombre Apellido Direccion
    Jose perez nom 258
    Jose fernandez esquin 258

    Tipo : contrato
    Actualizado el pago.

    Todo esto separado en las diferentes columnas del excel. Estuve intentando armar con utl_file pero no con buenos resultados no se si era porq yo lo armaba mal…agradeceria cualquier ayuda..
    Desde ya gracias!!

  2. Julio 30th, 2007 | 14:32

    entiendo el problema pero estas viendo la solucion por otro lado, con utl_file no puedes definir que celda de excel va a tener que dato, la solucion es generar un string con los valores separados por algo (comas, pipes, tabulador, etc) y esa cadena la guardas en el archivo linea por linea, al abrir eso en un excel te abre un wizard con opciones de como importar y listo

  3. vane
    Julio 31st, 2007 | 19:31

    bien mcuhas gracias ahora mismo me pongo a ver como lo soluciono…muy bueno el blog!!!

  4. Agosto 1st, 2007 | 11:35

    espero haberte ayudado, gracias, saludos

  5. Tales Klein
    Agosto 16th, 2007 | 10:25

    ¡ Que buen articulo! Felicitaciones. Lo voy a probar a ver si puedo usarlo a futuro en alguna implementación…

  6. Agosto 17th, 2007 | 21:16

    gracias, que bueno que les sirva, saludos

  7. Scarmet
    Agosto 20th, 2007 | 16:14

    Hola, necesito crear un archivo y enviarlo por mail pero no tengo privilegios en el servidor, ni un directorio donde depositarlo, por lo que el utl_file me provoca problemas para encontrar donde dejar el archivo, hay alguna manera de que le diga a Oracle que lo deje en mi maquina y despues lo tome y envie???

  8. Agosto 24th, 2007 | 16:21

    con utl_file no tienes acceso a ninguna maquina fuera de donde esta corriendo la base de datos, para usar utl_file forzosamente necesitas los privilegios sobre un directorio de ese servidor

  9. Octubre 2nd, 2007 | 11:08

    pues tal y como lo harias para otras cosas en windows “e:\directorio\” claro que al ser un paquete en la base de datos este directorio debe de ser del servidor base de datos

    como se obtiene?, lee de nuevo el post, saludos

  10. francisco
    Noviembre 22nd, 2007 | 15:04

    Subi los paquetes del blog y en marca error el procedimiento: ftp_files_stage … tienes otra version o podrias publicar el paquete ftp_interfase que tienes tu para probar move_fle.

    Saludos

  11. francisco
    Noviembre 22nd, 2007 | 16:46

    He probado algunas opciones de copiado de archivos en oracle pero al quer abrir el archivo marca error …

    Tienes Idea por que ?

    Los txt los pasa como si nada, con los binarios es que copia pero corruptos los archivos…

    PROCEDURE UTLTESTCOPY
    AS
    f1 UTL_FILE.file_type;
    BEGIN
    f1 := UTL_FILE.fopen (’GESTORDOC_DIR_R’, ‘busq_index.gif’, ‘r’);
    UTL_FILE.fcopy (src_location => ‘GESTORDOC_DIR_R’,
    src_filename => ‘busq_index.gif’,
    dest_location => ‘GESTORDOC_DIR’,
    dest_filename => ‘busq_index.gif’
    );
    UTL_FILE.fclose (f1);
    END;

  12. juan
    Noviembre 23rd, 2007 | 11:43

    marca error el pakete del blog .. cual usaste proporcionalo

  13. Noviembre 23rd, 2007 | 17:32

    “el paquete del blog” yo inserte el link para la descarga del paquete de una pagina externa, si marca error deberias de investigar mejor el error, a mi me funciono bien como esta

  14. Noviembre 23rd, 2007 | 17:38

    sobre el error al copiar, ya investigaste los demas parametros del procedure “fcopy” de utl_file? se me hace que le tienes que especificar como realizar la copia si ascii o binario (algo como en un cliente ftp)
    aparte de esto me queda la duda si realmente es necesario el abrir y cerrar el archivo (fopen y fclose) si solo quieres copiar el archivo, tal vez por ahi valla

  15. Mar
    Marzo 13th, 2008 | 1:09

    hola. estupendo tu artículo. Qué pena que no haya más gente como tú.
    Estoy desarrollando una aplicación que requiere que copie un fichero plano de un servidor a otro y tengo unas dudas con respecto a tu artículo.
    He montado el paquete de oracleportal en mi servidor desde el que disparo el procedimiento y testeo el move_file con GET, pero exactamente qué directorios hay que poner? los fisicos o los definidos en BD?. El usuario y password son de la bd de destino o del equipo? Puedes usar otro puerto que no sea el 21? Espero no ser muy pesada y reitero mis felicitaciones. un saludo

  16. Marzo 13th, 2008 | 12:01

    los directorios son fisicos, del servidor remoto y local, los usuarios son del servidor FTP remoto, el puerto depende del servidor FTP que puerto esta escuchando, saludos

  17. Juan
    Junio 3rd, 2008 | 16:29

    Muy bueno el articulo.
    Una pregunta el servidor local o remoto puede ser Windows / Linux? o viceversa?.
    Gracias :)

  18. Junio 3rd, 2008 | 20:26

    al estar usando un protocolo como FTP es independiente del sistema operativo, tu te conectas a un servicio remoto en el puerto 21 normalmente y si ese servicio esta sobre un windows, linux, unix, solaris no deberias de tener problemas

  19. JJ
    Junio 18th, 2008 | 10:32

    Hola Favor tu ayuda, tengo una pantalla en Forms 61,que debe ir ha ver/ buscar un archivo de texto en una ruta del servidor y ese archivo copiarlo localmente

    Favor tu ayuda urgente
    Gracias

  20. Junio 18th, 2008 | 14:06

    mmm es que directamente esta medio dificil, supongo que al decir “6i” estas trabajando en cliente/servidor por lo que se complica mas, la mas facil que se me ocurre, es que el archivo del servidor lo copies a una tabla de base de datos con UTL_FILE (suponiendo que ese archivo este en el servidor de la base de datos) ya con la info en la base, con text_io de forms generes el archivo localmente, espero haberte ayudado, saludos

  21. Jorge
    Julio 8th, 2008 | 11:16

    no me funciona necesito ftp_interface.verify_server
    ftp_interface.put
    ftp_interface.get

    gracias

  22. Julio 8th, 2008 | 12:18

    lo mejor es que vuelvas a leer el post, saludos

  23. peru
    Agosto 4th, 2008 | 5:16

    Hola, estoy utilizando el paquete utl_smtp para enviar correos y he visto que se define una variable como utl_tcp.crlf, pero al compilar me da error de restricción de implementación, no se puede acceder a una varible o cursor de paquete remoto. Estoy compialndo en local. Alguien me puede ayudar?
    MUchas gracias.

  24. Paco
    Septiembre 1st, 2008 | 10:03

    DonZote

    Rolate los fuentes que probastes tu, los del articulos no hacen lo que dice que hace.

    Subete un ZIP con los fuentes.

  25. Paco
    Septiembre 1st, 2008 | 10:11

    Donzonte:

    Subete un Zip con los fuentes que probastes, los del articulo no hace lo que dice que hace.

    Saludos

  26. Septiembre 2nd, 2008 | 2:38

    esta raro que no funcione, solo que lo hayan cambiado, ya tiene mas de un año que escribi este post, los mejor es que te bajes su ultima version y sobre esa trabajes, igual lo mio se tenga que modificar, saludos

  27. Septiembre 16th, 2008 | 13:19

    Estimado: no encuentro la libreria ftp_interface,
    donde puedo obtenerla!

  28. Septiembre 16th, 2008 | 21:26

    si leiste el post, seguro sabras de donde se descarga, saludos

Deja un comentario