- Blogzote.com - https://www.blogzote.com -

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);