将字节转换为二进制字符串

GPi*_*Pif 6 postgresql binary-data bytea

我需要解码一个 base64 字符串并获取一大块二进制文件。

Postgres 中是否有 SQL 函数可以简单地将 abytea转换为二进制字符串表示?
(例如“00010001010101010”。)

Erw*_*ter 8

如果您的 Postgres 安装使用默认设置运行bytea_output = 'hex',则有一个非常简单的技巧:

SELECT right(bytea_col::text, -1)::varbit;
Run Code Online (Sandbox Code Playgroud)

例子:

SELECT right((bytea '\xDEADBEEF')::text, -1)::varbit;
Run Code Online (Sandbox Code Playgroud)

结果:

'11011110101011011011111011101111'
Run Code Online (Sandbox Code Playgroud)

right(text, -1) 只是从文本表示中删除前导反斜杠的最便宜的方法。

varbit(标准 SQL 名称bit varying)用于任意长度的位串。将结果投射到textorvarchar如果你喜欢。

相关,有解释:


S-M*_*Man 3

演示:db<>小提琴

您可以将以下代码放入函数中:

WITH byte AS (   -- 1
    SELECT E'\\xDEADBEEF'::bytea as value
)
SELECT
    string_agg(      -- 5
        get_byte(value, gs)::bit(8)::text -- 4
        , ''
    )
FROM 
    byte,
    generate_series(        -- 3
        0, 
        length(value) - 1   -- 2
    ) gs
Run Code Online (Sandbox Code Playgroud)

我在小提琴中演示了查询的开发。

  1. WITH子句封装了bytea在进一步代码中双重使用的值
  2. length()bytea计算值的二进制长度
  3. generate_series()0创建一个从到 的列表length - 10 - 3在我的示例中)
  4. get_byte()第二次获取该bytea值并给出位置处的字节gs(之前计算的值0-3)。这给出了integer字节的表示。之后,转换为类型bit(8)将此函数的结果转换为其二进制表示形式(1 字节 = 8 位)
  5. string_agg()最后将所有二进制字符串聚合为一个。(采用其text表示形式而不是bit类型,没有分隔符)

函数可能如下所示:

CREATE OR REPLACE FUNCTION to_bit(value bytea) RETURNS SETOF text AS 
$$
BEGIN
    RETURN QUERY 
        SELECT
            string_agg(get_byte(value, gs)::bit(8)::text, '')
        FROM 
            generate_series(0, length(value) - 1) gs;
END;
$$ LANGUAGE plpgsql;
Run Code Online (Sandbox Code Playgroud)

之后你可以这样称呼它:

SELECT to_bit(E'\\xDEADBEEF'::bytea)
Run Code Online (Sandbox Code Playgroud)

您可以尝试使用get_bit()而不是get_byte(). 这可以保证::bit(8)演员阵容的安全,但当然你确实需要将长度乘以系数8

生成的位字符串具有另一个位顺序,但也许它更适合您的用例:

WITH byte AS (
    SELECT E'\\xDEADBEEF'::bytea as value
)
SELECT
    string_agg(get_bit(value, gs)::text, '')
FROM 
    byte,
    generate_series(0, length(value) * 8 - 1) gs
Run Code Online (Sandbox Code Playgroud)

演示:db<>小提琴