UNIX 命令 file根据文件的内容确认一个文件类型,而不是使用文件扩展名。例如,每个 GIF 文件都以字符 GIF开始,每个 JPEG 文件都以big-endian序的值 oxffd8 开始。
file命令要查询一个 ASCII 文本文件,该文件一般位于 /etc/magic 中。你可以在一台 UNIX 机器的 man 页查看 magic 来浏览其格式。在 Apache Web 服务器上也有类似的文件。它一般用来确认自己不知道的扩展名的文件,然后返回正确的 MIME 类型。Apache 的版本很简单,其处理范围只包含一些很可能出现在 Web 服务器中的文件。 数据库可以使用一个相似的技术来确定一个 BLOB 列的 MIME 类型。大多数据库应用程序在存储数据的时候还会存储某种类型的标识。然而,可能对于某些人来说不能正确地标识数据。因此,通过直接分析数据来检查 BLOB 值的 magic 值然后返回一个 MIME 类型和解码信息将会很有用。 将magic安装到数据库 安装 magic 的过程使用一个 Perl 脚本产生一种可以使用 SQL*Loader 装载到数据库的标准化格式。数据然后由一个 PL/SQL 函数来扫描,该函数试图确定 BLOB 的数据。下面是建立数据的步骤,以及一个例子: 第一步:创建一个 Perl 脚本将 magic 转成一个 SQL*Loader 数据文件: #!/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 ($dteq '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 ($dteq 'belong') { $data = sprintf('%02X' x 4,unpack('C4',pack('N',$cnt))); } elsif ($dteq 'lelong') { $data = sprintf('%02X' x 4,unpack('C4',pack('V',$cnt))); } elsif ($dteq 'beshort' $dteq 'short') { $data = sprintf('%02X' x 2,unpack('C2',pack('n',$cnt))); } elsif ($dteq 'leshort') { $data = sprintf('%02X' x 2,unpack('C2',pack('v',$cnt))); } elsif ($dteq 'byte') { $data = sprintf('%02X',$cnt); } else { warn "data type '$dt' not implemented"; } } $i++; print join(',',$i,$cont,$offset,$data,$mime,$encoding),"\n"; } close(FILE); $ perl magicdata.pl $Oracle_HOME/Apache/conf/magic > magicdata.dat 第二步:在 SQL*Plus 中使用下面的 SQL 脚本创建表来保存这个数据: create table magicdata ( line integer, cont char(1), offset integer, data raw(24), mime varchar2(24), encoding varchar2(10) ); 第三步:使用 SQL*Loader 将前面产生的数据装载到数据库中: load data truncate into table magicdata fields terminated by ',' optionally enclosed by '"' trailing nullcols ( line, cont, offset, data, mime, encoding ) $ sqlldr user=scott/tiger control=magicdata.ctl data=magicdata.dat 下面是一些测试数据,只有一个 BLOB 列的一个简单的表。
drop table magictest; create table magictest (myblob blob); 第四步:使用 SQL*Loader 从文件装载三个图像到这个表: load data infile * into table magictest fields terminated by ',' ( fname filler, "MYBLOB" lobfile(fname) terminated by eof ) begindata file.bmp file.gif file.jpg $sqlldruserid=scott/tiger control=magictest.ctl 下面是扫描 magic 数据表和 BLOB 以确定文件 MIME 类型的 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; 现在为了显示它确实可以工作,我运行下面的 SQL 语句: Select magic(myblob) from testdata; 得到的输出是: MAGIC(MYBLOB) ------------- image/bmp image/gif image/jpeg
|