Oracle – Identificar el tipo de archivo de una columna BLOB

febrero 4, 2010

En linux existe un comando llamado “file” que te permite saber el tipo de un archivo de acuerdo a su contenido y no de acuerdo a su extensión, como lo hace el windoze. Asi que, ¿cómo podemos hacer para saber el tipo de archivo de un campo BLOB?

Requisitos:
Perl
Oracle Client (SQL Loader, SQL Plus)

1.- Copia y pega el siguiente texto en un archivo nuevo y nombralo “magicdata.pl”

#!/usr/local/bin/perl
# — magicdata.pl

# scan the “magic” file for file identification rules
$filename = ($#ARGV>=0) ? $ARGV[0] : ‘magic’;
open(FILE,”<$filename”) || die “Couldn’t open file ‘$filename'”;
$i = 0;
while (<FILE>)
{
next if /^\s*#/;    # skip comments
next if /^\s*$/;    # skip blank lines
s/[\r\n]*//g;       # strip trailing cr/lf
# replace octal escape codes
s/\\([0-9]{3})/pack(‘C’,oct($1))/eg;
# split on spaces, except for “\ ”
my ($offset,$dt,$cnt,$mime,$encoding) = split(/(?<!\\)\s+/);
$cont = ($offset =~ /^>/) ? ‘Y’ : undef;
$offset = substr($offset,1) if $cont;
if ($dt eq ‘string’)
{
# generate a HEXTORAW version of the string
$data = join(”,map(sprintf(‘%02X’,$_),unpack(‘C*’,$cnt)));
}
else
{
# handle special number formats
if ($cnt =~ /^0x/) { $cnt = hex($cnt); }    # hex
elsif ($cnt =~ /^0/) { $cnt = oct($cnt); }  # octal
warn “unknown number: ‘$cnt'” unless $cnt =~ /^([0-9]|[1-9][0-9]*)$/;
if ($dt eq ‘belong’) {
$data = sprintf(‘%02X’ x 4,unpack(‘C4’,pack(‘N’,$cnt)));
} elsif ($dt eq ‘lelong’) {
$data = sprintf(‘%02X’ x 4,unpack(‘C4’,pack(‘V’,$cnt)));
} elsif ($dt eq ‘beshort’ || $dt eq ‘short’) {
$data = sprintf(‘%02X’ x 2,unpack(‘C2’,pack(‘n’,$cnt)));
} elsif ($dt eq ‘leshort’) {
$data = sprintf(‘%02X’ x 2,unpack(‘C2’,pack(‘v’,$cnt)));
} elsif ($dt eq ‘byte’) {
$data = sprintf(‘%02X’,$cnt);
} else {
warn “data type ‘$dt’ not implemented”;
}
}
$i++;
print join(‘,’,$i,$cont,$offset,$data,$mime,$encoding),”\n”;
}
close(FILE);

2.- Ejecuta el siguiente comando en una terminal (consola)

perl magicdata.pl $ORACLE_HOME/Apache/conf/magic > magicdata.dat

Si no tienes o no encuentras el archivo $ORACLE_HOME/Apache/conf/magic puedes utilizar el “sample magic file” que encuentras aquí. Nota: a mi no me detectaba los archivos RTF, modifiqué el magic file la línea que dice

0    string        {\\rtf        application/rtf

por

0    string        {\rtf        application/rtf

y ya me funcionó.

3.- Crea una tabla para almacenar los registros que nos genero el comando anterior

create table magicdata
(
line        integer,
cont        char(1),
offset      integer,
data        raw(24),
mime        varchar2(24),
encoding    varchar2(10)
);

4.- Crea un archivo llamado “magicdata.ctl” y pega lo siguiente. Este será nuestro archivo de control del SQL Loader.

load data
truncate
into table magicdata
fields terminated by ‘,’ optionally enclosed by ‘”‘
trailing nullcols
(
line,
cont,
offset,
data,
mime,
encoding
)

5.- Carga los registros en la tabla mediante el SQL Loader (puede ser desde una terminal o desde una interfaz grafica) con el siguiente comando:

sqlldr user=scott/tiger@TNSNAMES_ID control=magicdata.ctl data=magicdata.dat

donde TNSNAMES_ID es el identificador de la base de datos, del archivo tnsnames.ora, donde creaste la tabla.

6.- Ahora hay que crear la siguiente funcion de PL/SQL

create or replace function magic(lob_loc blob) return varchar2
is
continued boolean := false;
bdata raw(100);
begin
for rec in (select * from magicdata order by line) loop
if rec.cont = ‘Y’ then
if continued then
bdata := dbms_lob.substr
(
lob_loc,
utl_raw.length(rec.data),
rec.offset+1
);
if utl_raw.compare(bdata,rec.data) = 0 then
return rec.mime;
end if;
end if;
else
bdata := dbms_lob.substr
(
lob_loc,
utl_raw.length(rec.data),
rec.offset+1
);
dbms_output.put_line(bdata||’ <=> ‘||rec.data);
if utl_raw.compare(bdata,rec.data) = 0 then
if rec.mime is null then
continued := true;
else
return rec.mime;
end if;
end if;
end if;
end loop;
return null;
end magic;
/
show errors;

7.- Si todo salió bien, ya podemos utilizar nuestra función de la siguiente forma

select magic(myblob) from mytable;

Y obtendremos algo asi, de acuerdo a los tipos de archivos de nuestra tabla

MAGIC(MYBLOB)
————-
image/bmp
image/jpeg
application/rtf

Fuentes:
Oracle Tip – Tech Republic
tnsnames.ora – Oracle FAQ
MIME Types – Wikipedia
Perl.org

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: