将文件表(存储为bytea)复制到磁盘上的单个文件中?

时间:2012-11-11 21:04:34

标签: bash postgresql shell copy

使用postgresql 8.4中的COPY命令导出bytea类型的数据,这对于单个记录可以正常工作:

copy (SELECT encode(test_column, 'hex') FROM test_table LIMIT 1) TO '/home/user/file.hex'

之后,我使用xxd命令获取适当的文件类型。 如果这是一个非常菜鸟问题,请提前抱歉,但是可以将所有记录导出到file-1,file-2 ... file-n吗?什么是正确的语法或脚本?我似乎无法在postgresql副本中找到它。
例如,这是单行的bash脚本:

#!/bin/bash

psql \  
    -P t \  
    -P format=unaligned \  
    -X \  
    -U myuser \  
    -h myhost \  
    -c "select my_bytea_col from my_table where id=1" \  
    mydb \  
| xxd -r -p > dump.txt  

然而,我需要在所有ID上执行它并将它们保存在不同的文件下,例如file1.txt,file2.txt,file3.txt ..等等。
也可能非常有趣的是能够使用另一列的数据(例如id)来相应地命名生成的hex文件。

1 个答案:

答案 0 :(得分:3)

我使用的脚本语言直接支持PostgreSQL。

这给了一个名为regress的数据库非常好的工作,该数据库包含一个名为files的表,列fileid(整数)和filedata(bytea)。它将数据写入outdir变量指定的目录中的文件,在根据{filenameprefix}{fileid}{filenamesuffix}之类的模式命名的文件中。

#!/usr/bin/env python3
import os
import sys
import psycopg2

outdir = "files"
filenameprefix = "f"
filenamesuffix = ""

def main():
        os.makedirs(outdir, exist_ok=True)
        conn = psycopg2.connect("dbname=regress")
        curs = conn.cursor();
        curs.execute("SELECT fileid, filedata FROM files;")
        for (fileid, filedata) in curs:
            fn = filenameprefix+str(fileid)+filenamesuffix
            f = open(os.path.join(outdir, fn), "wb")
            f.write(filedata)
            f.close()
        conn.close();

if __name__ == '__main__':
        main()

我使用此代码创建上述脚本中引用的测试环境:

#!/usr/bin/env python3
import psycopg2
conn = psycopg2.connect("dbname=regress")
curs = conn.cursor()
curs.execute('CREATE TABLE files(fileid serial primary key, filedata bytea);')
for i in range(1,10)
    curs.execute('INSERT INTO  files(filedata) VALUES (%s);', (psycopg2.Binary(open('/dev/urandom','rb').read(1024)),))

编辑:为了使它与您在问题中使用的命名相同,我刚才假设是通用的匿名名称,请更改:

  • regress - >无论您的数据库名称是什么
  • files - > my_table
  • fileid - > id
  • filedata - > my_bytea_col

这个脚本的等价物可以在bash中完成,这很麻烦。您需要使用协同进程以事务安全的方式执行此操作。您需要创建一个psql协同进程并在其中打开SERIALIZABLE事务,然后在SELECT fileid FROM files中打开一个shell变量。将shell变量和每个ID SELECT filedata FROM files循环到xxd管道中,转到使用ID上的字符串插值创建的文件名。

IMO:不值得麻烦,使用一种脚本语言,为您提供直接的PostgreSQL访问。

如果您不需要交易安全,那就更容易了;只需在一个psql调用中获取ID,然后在后续文件中获取文件数据。它会更慢,不会对交易安全,但它会更容易。