我们如何获得mime-type的bytea 存储在Postgres数据库中?
答案 0 :(得分:1)
在您首先存储bytea
时,除了将其分配给其他字段外,无法明确地知道MIME类型。
假设您有未知类型的字节数组来表示可能具有MIME类型的文件或其他合理完整的对象,您可以像使用文件一样使用MIME类型的猜测工具。这些工具远非完美,但适用于具有常规和可预测标头的常见性能良好的文件类型。
PostgreSQL没有内置这样的工具,但PostgreSQL支持调用PL / Python和PL / Perl等过程语言。这些语言做具有MIME类型猜测工具。
所以我建议在PL / Perl或PL / Python中编写一个包装函数,它使用适当的MIME类型猜测库来探测bytea
参数并返回猜测的MIME类型。图书馆选择和实施的细节留给读者练习;我将从PL / Perl或PL / Python上的PostgreSQL手册开始,无论您喜欢使用哪种。
答案 1 :(得分:0)
我知道答案有点晚,但会帮助其他人。
根据@ craig-ringer的建议,我在plpythonu
中实现了mime-magic,所以我可以在INSERT / UPDATE-Trigger中使用该函数。
在数据库服务器上为postgresql版本安装plpythonu
(例如,通过apt-get
或yum
)。不需要重新启动/重新加载数据库,因此可以在生产中轻松完成。
然后在数据库服务器上安装python模块magic
:
pip install python-magic
之后在您的数据库中创建plpythonu语言:
CREATE LANGUAGE plpythonu;
现在您可以在python中编写数据库函数(甚至是导入python模块):
CREATE OR REPLACE FUNCTION mimemagic(data bytea) RETURNS TEXT AS $$
import magic
return magic.from_buffer(data, mime=True)
$$ LANGUAGE plpythonu;
如果使用python2,postgresql的BYTEA
类型将映射到python的string
类型。
对于python 3,它映射到pythons bytes
类型。
创建函数后,可以像任何其他postgresql函数一样在任何语句或触发器函数中使用plpythonu函数。 要测试我们的函数,我们可以创建一个如下所示的表并插入一些文件:
CREATE TABLE public.files (
file_id BIGINT PRIMARY KEY NOT NULL DEFAULT nextval('files_file_id_seq'::regclass),
name TEXT NOT NULL,
extension TEXT,
content BYTEA NOT NULL,
mime_type TEXT
);
示例查询:
SELECT name, extension, mime_type, mimemagic(content) FROM files;
结果:
name | extension | mime_type | mimemagic
----------------------------------+-----------+-----------+-----
10868_170915_1M | pdf | | application/pdf
30567_160415_1M | pdf | | application/pdf
Diode-SCS | dxf | | text/plain
Config | zip | | application/zip
btn-default-medium-focus-corners | gif | | image/gif
_loadmask | scss | | text/plain
mr | json | | text/plain
10549_160415_2M | pdf | | application/pdf
disconnect | png | | image/png
正如您所看到的,表中没有保存mime_type,但是根据需要检测到mime-type。
不需要说每个查询的每一行都执行一个函数是一个巨大的性能损失,所以mime类型检测应该在INSERT / UPDATE和缓存上完成:
示例触发器:
CREATE OR REPLACE FUNCTION files_trigger()
RETURNS TRIGGER AS $$
BEGIN
IF (TG_OP = 'INSERT') OR (TG_OP = 'UPDATE' AND new.content IS DISTINCT FROM old.content)
THEN
new.mime_type := mimemagic(new.content);
END IF;
RETURN new;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER files_insertupdate_trigger BEFORE INSERT OR UPDATE ON files
FOR EACH ROW EXECUTE PROCEDURE files_trigger();
现在检测到Mime Type一次,并保存在filecontent旁边:
SELECT name, extension, mime_type FROM files;
结果:
name | extension | mime_type
------------------------------------------+-----------+------------------------------
teamviewer_10.0.35509_amd64 | deb | application/x-debian-package
BDFE999CCC39110229563FA8C8583E239F6BDBA1 | log | text/plain
daccr-Download | exe | application/x-dosexec
为了获得更好的结果,您应该在可用的情况下尝试基于文件名/扩展的检测,因为某些类型的mimemagic单独失败(json-File被检测为text / plain)。
也可以使用像uncompress=True
这样的魔术选项,它可以提供更多可用的结果:
>>> import magic
>>> import mimetypes
>>> filename='verybig.json.gz'
>>> m=magic.Magic(mime=True, uncompress=False)
>>> m.from_file(filename)
'application/gzip'
>>> m=magic.Magic(mime=True, uncompress=True)
>>> m.from_file(filename)
'text/plain'
>>> mimetypes.guess_type(filename)
('application/json', 'gzip')
>>>
plpythonu的文档可以在这里找到:http://www.postgresql.org/docs/9.5/static/plpython.html
python的魔术模块的代码和文档可以在这里找到:https://github.com/ahupp/python-magic