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