2011-06-14 103 views
3

我正在使用COPY從表中複製一個字段到一個文件。這個字段是一個壓縮文本文件,所以我使用二進制副本。 該文件被創建,唯一的問題是COPY向文件中添加了一個頭文件和一個尾部文件(?),這是我不需要的。這可以改變嗎?是否有一個參數可以導致COPY將該字段完全保存爲數據庫中的字段?postgres複製命令,二進制文件

如果我手動刪除不需要的標頭,我可以用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 

任何想法?

回答

1

你確定這是將數據庫中的壓縮文本存儲爲二進制文件的最佳方法嗎?據documentation長文本隱含/自動壓縮:

長字符串由 系統自動壓縮,因此在磁盤上的物理 需求可能會較少。 非常長的值也存儲在 背景表中,因此它們不會影響 快速訪問較短的 列值。在任何情況下, 可以存儲的最長可能字符串大約爲1 GB。

+0

我同意這是不是:-)最好的方式,但我不是一個誰決定這樣做,我只需要讓它離開那裏:-) – user797710 2011-06-15 07:25:02

1

我不知道一個簡單的方法... COPY具有可變長度頭的二進制格式,不是很容易「修剪」。除此之外,PG是相當文本爲中心的,我不知道有什麼辦法可以強制SELECT的BYTE字段的「原始」(二進制)輸出。

你可以得到一個文本的十六進制輸出,並自己寫一個小程序(C,Perl或其他),將它從\x000102414243轉換爲二進制。並不難,但不是直接的(和十六進制格式是在PostgreSQL 9.0)

psql -t -q -c "select binaryfield from.. where ..." mydb | myhextobin > tmp.gz 

BTW,格熱戈日的回答很中肯。

補充:不是很乾淨,也不是萬無一失的,只是如果有什麼發現它有用......

/* 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; 
} 
0

它不建議去試圖解碼PostgreSQL的二進制格式。僅僅因爲你使用的測試文件並不意味着所有的東西都能正常工作。例如,可能某些字符序列(不會出現在您的測試文件中)會被轉義。

+0

我不明白。如果'b'是一個'bytea'字段(我認爲),它們將輸出一個十六進制字符串,而不是原始二進制內容。 (我沒有downvote) – leonbloy 2011-06-14 14:51:01

+0

@leonbloy:是的,沒有指定數據的類型。實際的輸出格式取決於bytea_output() - 儘管默認格式都是編碼格式。 PostgreSQL不支持內聯blob類型,只是引用大對象。 – 2011-06-14 14:59:11

3

一種可能性,它的工作原理雖然你可能不喜歡它:

psql -At -c "select encode(content, 'base64') from t where ..." | base64 -d 

即打印的內容爲base64和解碼。我認爲現實是,psql旨在產生可讀的輸出,並說服它放棄原始二進制數據是故意困難的。

我想如果你想足夠的話,你可以編寫一些工具(Perl/python腳本)來連接數據庫並直接打印原始輸出。

COPY的「WITH BINARY」選項不只是做一個簡單的二進制輸出,它執行一些可能依賴的可疑編碼。

+0

它的作品,我喜歡它!謝謝!! – user797710 2011-06-15 07:16:42

0

您可能會發現使用具有客戶端驅動程序和讀取bytea類型的語言來執行此操作更容易:PHP,python,ruby,perl,javascript,java等。只需在那裏執行查詢,使用可能已經存在於該語言中的gzip庫,並寫出該文件。

或者,您可以在數據庫中使用過程語言並創建存儲過程。您可以將請求的文件名傳遞給存儲過程。

+0

或者,我喜歡Araqnid關於使用類型爲base64的'encode()'的答案。 – justis 2011-06-15 08:28:15

0

複製命令完成這項工作。您只需告訴:--no-align--tuples-only

●對於壓縮,使用gzip PSQL之間和文件

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