如何获取存储在PostgreSQL中的MIME类型的bytea

如何获取存储在PostgreSQL中的MIME类型的bytea,postgresql,bytearray,postgresql-9.2,postgresql-9.3,bytea,Postgresql,Bytearray,Postgresql 9.2,Postgresql 9.3,Bytea,我们怎样才能得到哑剧类型的bytea 存储在Postgres数据库中?当您首先存储bytea时,除了将MIME类型分配给另一个字段之外,无法确定MIME类型 假设您有未知类型的字节数组来表示文件或其他可能具有MIME类型的合理完整的对象,您可以像对文件一样使用MIME类型猜测工具。这些工具远非十全十美,但对于具有规则和可预测头的常见行为良好的文件类型来说,它们工作得很好 PostgreSQL中没有内置这样的工具,但PostgreSQL支持调用过程语言,如PL/Python和PL/Perl。这些语

我们怎样才能得到哑剧类型的bytea
存储在Postgres数据库中?

当您首先存储
bytea
时,除了将MIME类型分配给另一个字段之外,无法确定MIME类型

假设您有未知类型的字节数组来表示文件或其他可能具有MIME类型的合理完整的对象,您可以像对文件一样使用MIME类型猜测工具。这些工具远非十全十美,但对于具有规则和可预测头的常见行为良好的文件类型来说,它们工作得很好

PostgreSQL中没有内置这样的工具,但PostgreSQL支持调用过程语言,如PL/Python和PL/Perl。这些语言确实有MIME类型猜测工具


因此,我建议在PL/Perl或PL/Python中编写一个包装器函数,使用适当的MIME类型猜测库来探测
bytea
参数并返回猜测的MIME类型。图书馆选择和实施的细节留给读者练习;我将从关于PL/Perl或PL/Python的PostgreSQL手册开始,无论您喜欢使用哪一种。我知道答案有点晚,但会对其他人有所帮助

根据@craig ringer的建议,我已经在
plpythonu
中实现了mime魔术,因此我可以在插入/更新触发器中使用该函数

在数据库服务器上,为您的postgresql版本安装
plpythonu
(例如,通过
apt-get
yum
)。无需重新启动/重新加载数据库,因此可以在生产环境中轻松完成

然后在数据库服务器上安装python模块
magic

pip install python-magic
之后,在数据库中创建plpythonu语言:

CREATE LANGUAGE plpythonu;
现在可以用python编写数据库函数(甚至可以导入python模块):

如果使用python2,postgresql的
BYTEA
类型映射到python的
string
类型。 对于Python3,它映射到pythons
bytes
type

创建函数后,可以像其他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
                   name                   | extension |          mime_type           
------------------------------------------+-----------+------------------------------
 teamviewer_10.0.35509_amd64              | deb       | application/x-debian-package
 BDFE999CCC39110229563FA8C8583E239F6BDBA1 | log       | text/plain
 daccr-Download                           | exe       | application/x-dosexec
如您所见,表中未保存mime_类型,但会根据需要检测到mime类型

不用说,对每个查询的每一行执行一个函数会对性能造成巨大影响,因此应该在插入/更新时进行mime类型检测并缓存:

触发器示例:

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类型现在检测一次并保存在filecontent旁边:

SELECT name, extension, mime_type 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
                   name                   | extension |          mime_type           
------------------------------------------+-----------+------------------------------
 teamviewer_10.0.35509_amd64              | deb       | application/x-debian-package
 BDFE999CCC39110229563FA8C8583E239F6BDBA1 | log       | text/plain
 daccr-Download                           | exe       | application/x-dosexec
为了获得更好的结果,如果可用,还应该尝试基于filename/-extension的检测,因为只有mimemagic无法检测某些类型(json文件被检测为text/plain)。 还可以使用magic的选项,如
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的文档可在以下位置找到:


python神奇模块的代码和文档可以在这里找到:

首先将其存储在另一列中。您能告诉我关于PL/Perl或PL/python脚本的情况,以及如何在Postgres中应用它们。@ripunj2408813。您需要使用适当的库(如Perl的
File::Type
或Python的mimetypes或Python Magic库)用Perl或Python编写一个过程。试一试。如果您陷入困境,请发布一个新问题,并提供适当的详细信息,说明您尝试了什么以及您陷入困境的地方。我不知道Perl脚本。您能否提供Perl脚本以获取Postgres中bytea的mime类型。@ripunj2408813请尝试自己编写。你可能需要先学习一下。堆栈溢出不是一种代码编写服务,虽然我很乐意提供帮助,但只有在您做出一些努力的情况下,我才会这样做。请参阅我最后一个链接中的文档。