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

标签 postgresql arrays postgresql-9.2 postgresql-9.3 bytea

如何获取bytea的mime类型 存储在 Postgres 数据库中?

最佳答案

我知道答案有点晚了,但会帮助其他人。

正如@craig-ringer 所建议的,我已经在 plpythonu 中实现了 mime-magic,因此我可以在我的 INSERT/UPDATE-Trigger 中使用该函数。

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

然后在数据库服务器上安装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 类型。

不用说,对每个查询的每一行执行一个函数是一个巨大的性能损失,所以 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 类型现在被检测一次并保存在文件内容旁边:

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 被检测为文本/纯文本)。 也可以使用 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 的文档可以在这里找到:http://www.postgresql.org/docs/9.5/static/plpython.html

python 的 magic 模块的代码和文档可以在这里找到:https://github.com/ahupp/python-magic

关于postgresql - 如何获取存储在 PostgreSQL 中的 bytea 的 MIME 类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31445386/

相关文章:

c - 我需要帮助解决这个 C 代码,请

stored-procedures - SQLAlchemy 从 postgresql 存储过程获取输出参数

python - PostgreSQL 和 Python

sql - 按 60 分钟持续时间对记录进行分组,从第一条记录的时间戳开始小时

r - 如何将所有转义字符保留在 SQL 字符串中以使用 R 查询 POSTGRES 数据库?

postgresql - 从 sql 格式转储恢复 pythonanywhere 上的 postgresql

arrays - 一次仅删除一个元素后,查找从父数组产生的已排序数组的数量

python - 将多个 2d numpy 数组放入 3d numpy 数组

postgresql-9.2 - 如何更改 PostgreSQL 数据目录?

postgresql - 在函数中使用来自 for 循环的值