我正在使用COPY将字段从表复制到文件。这个字段是一个压缩文本文件,所以我使用二进制副本。 创建文件时,唯一的问题是COPY会在文件中添加标题和预告片(?),这是我不需要的。可以改变吗?是否有一个参数可以导致COPY将字段与数据库中的字段完全相同?
如果我手动删除不需要的标题,我可以使用zcat或gunzip提取文件。
我正在做这样的事情:
psql -d some_database -c \
"copy (select some_column from a_table where id=900) to stdout with BINARY;" > /tmp/tmp.gz
然后我想做
gunzip /tmp/tmp.gz
有什么想法吗?
答案 0 :(得分:3)
一种可能性,虽然您可能不喜欢它,但仍有效:
psql -At -c "select encode(content, 'base64') from t where ..." | base64 -d
即。将内容打印为base64并对其进行解码。我认为现实是psql旨在产生可读输出,并且说服它去除原始二进制数据是故意的。
我想如果你想要的话,可以编写一些工具(Perl / python脚本)来连接数据库并直接打印原始输出。
" WITH BINARY" COPY的选项并不只是做一个简单的二进制输出,它执行一些可能依赖的编码。
答案 1 :(得分:1)
您确定将压缩文本存储在数据库中作为二进制文件的最佳方法是什么?根据{{3}}长文本被隐式/自动压缩:
长字符串被压缩 系统自动,所以物理 磁盘上的要求可能会更少。 非常长的值也存储在 背景表,所以他们没有 干扰快速访问更短 列值。无论如何, 最长的字符串 可以存储大约1 GB。
答案 2 :(得分:1)
我不知道一种直截了当的方式...... COPY有一个带有可变长度标题的二进制格式,不太容易“修剪”。除此之外,PG是以文本为中心的,我不知道有没有办法从SELECT强制BYTEA字段的“原始”(二进制)输出。
你可以得到一个文本的十六进制输出并自己写一个小程序(C,perl或其他)来将它从说\x000102414243
转换为二进制。不难,但不是直截了当(十六进制格式在Postgresql 9.0中)
psql -t -q -c "select binaryfield from.. where ..." mydb | myhextobin > tmp.gz
顺便说一句,Grzegorz的回答是非常恰当的。
补充:不是很干净,也不是万无一失,只要有些东西发现它有用......
/* expects a pg hexadecimal string, in "\x....." format, and converts to binary*/
/* warning: no checks! it just ignores chars outside [0-9a-f] */
#include<stdio.h>
int main() {
int x, pos, v;
char hex[3]={0,0,0};
pos = 0;
while( (x = getchar()) >= 0) {
if(( x >='0' && x <= '9') || ( x >= 'a' && x <= 'f' )) {
hex[pos++] = (char)x;
if(pos == 2) {
sscanf(hex, "%x", &v);
putchar((char)v);
pos = 0;
}
}
}
return pos==0 ? 0 : 1;
}
答案 3 :(得分:0)
不建议尝试解码postgresql二进制格式。仅仅因为你正在使用的测试文件并不意味着一切都会起作用。例如,某些字符序列(未出现在测试文件中)可能会被转义。
答案 4 :(得分:0)
您可能会发现使用具有客户端驱动程序并且能够读取bytea类型的语言更容易:PHP,python,ruby,perl,javascript,java等。只需在那里执行查询,使用gzip可能已经存在于该语言中的库,并写出该文件。
或者,您可以在数据库中使用过程语言并创建存储过程。您可以将请求的文件名传递给存储过程。
答案 5 :(得分:0)
复制命令可以完成这项工作。您只需说出:--no-align
和--tuples-only
。
对于压缩,请在psql和文件
之间使用gzip
psql --tuples-only --no-align -d some_database -c \
"copy (select some_column from a_table where id=900) to stdout with BINARY;" | gzip > /tmp/tmp.gz