
Contents
- 実行環境
- 出力用サンプルデータ
: PostGIS ラスタを PNG に変換したもの - いくつか方法はあるけど、今回は
COPY ... FORMAT BINARY の結果をトリム - COPY ... FORMAT BINARY
の結果をバイナリエディタで開き、先頭を削る - dd
コマンドの Windows 版を使い、コンソールでバイナリファイルの先頭を削る - 完成形はクエリ一つ、COPY ... TO PROGRAM 'dd ...' (FORMAT BINARY)
- 今後の課題
: COPY ... FORMAT BINARY のヘッダサイズが変わるケース - 関連リンクまとめ
- 来年もよろしくお願いします
m(_)m 補足記事(2016年1月2日): xxd コマンドを使う場合
実行環境
- Windows 7 64
bit - PostgreSQL 9.5 RC
1(zip 版からバッチファイルで起動) - PostGIS 2.2.0(byteaデータのサンプルを作る用。インストール手順はこちら)
- コマンドプロンプトの代わりにConEmu 151208 + psql
出力用サンプルデータ : PostGIS ラスタを PNG に変換したもの
bytea-- 出力結果をデータだけにする \pset tuples_only on \pset format unaligned -- 適当なジオメトリ → ラスタ → PNG select st_asPNG( st_asRaster( st_buffer( st_point(1, 5), 10 ), 150, 150, '8BUI' ) );

この出力をそのままファイルに保存してもテキストになってしまうので、何か工夫して
いくつか方法はあるけど、今回は COPY ... FORMAT BINARY の結果をトリム
PostgreSQL- PL/Python
など「bytea 型をバイナリとして扱う」「データをローカルファイルに出力する」の両方ができる組み込み言語を使う。2 年くらい前、PL/Python でできた一方、PL/R は何か前者がうまくいかず断念。ただ当時の自分のスキル不足が原因かもしれず、いずれ再確認します。 - encode
関数でいったん Base64 形式(テキスト)で出力し、Base64 をデコードできる外部プログラムでバイナリに戻す。Base64 は古くからあるので、使える言語・ライブラリは豊富。 - 上と似てますが、bytea
型をいったんテキストとして出力し(hex 書式またはエスケープ書式になる)、書式の規則にのっとってバイナリに戻すプログラムを自作する。StackOverflow - postgres copy command, binary fileの真ん中あたりに、hex → bin の例があります。 - COPY
コマンドに FORMAT BINARY オプションを付けて出力すると、ヘッダ + バイナリデータというファイルになるので、外部プログラムでヘッダだけ削除する。
StackOverflow
COPY
COPY ... FORMAT BINARY の結果をバイナリエディタで開き、先頭を削る
COPYcopy ( -- 適当なジオメトリ → ラスタ → PNG select st_asPNG( st_asRaster( st_buffer( st_point(1, 5), 10 ), 150, 150, '8BUI' ) ) ) to 'R:/tmp.bin' (format binary);

出力された

もう一つサイズの大きいバイナリを作成し、ヘッダ範囲が異なるか確認。先ほどの「縦横
select st_asPNG( st_asRaster( st_buffer( st_point(1, 5), 10 ),1500, 1500, '16BUI' -- ここだけ変更 ) )
↓ 両者を

Stirling


参考まで、各ファイルを

dd コマンドの Windows 版を使い、コンソールでバイナリファイルの先頭を削る
前項のバイナリエディタの作業を、今度はコンソールのコマンド実行に置き換えます。そうすればウェブ検索すると
dd if=入力ファイル bs=1 skip=先頭の削るバイト数 of=出力ファイル
次に、Windows

↓ 先頭
:: 対象ファイル確認 $ dir *.bin :: ddコマンドのパスを環境変数に入れる $ set dd=D:\AppsPortable\GitPortable\2.6.2\App\Git\usr\bin\dd :: バイナリ先頭のヘッダを削る $ %dd% if=tmp.bin bs=1 skip=25 of=tmp.bin.dd.png $ %dd% if=tmp_large.bin bs=1 skip=25 of=tmp_large.bin.dd.png


完成形はクエリ一つ、COPY ... TO PROGRAM 'dd ...' (FORMAT BINARY)
今回必要な-- on psql copy ( bytea型を一行だけ返すクエリ ) to 一時ファイル (format binary); -- on console dd if=一時ファイル bs=1 skip=25 of=出力ファイル
ところで
copy ( bytea型を一行だけ返すクエリ ) to program 'dd bs=1 skip=25 of=出力ファイル' (format binary);
↓ 実際にやってみた様子。ユーザは
copy ( select st_asPNG( st_asRaster( st_buffer( st_point(1, 5), 10 ), 150, 150, '8BUI' ) ) ) to program '"D:/AppsPortable/GitPortable/2.6.2/App/Git/usr/bin/dd" bs=1 skip=25 of="R:/st_aspng_test.png"' (format binary);

実際に出力された
今後の課題 : COPY ... FORMAT BINARY のヘッダサイズが変わるケース
ドキュメントの関連リンクまとめ
- PostgreSQL 9.4.5
文書 : バイナリ列データ型 - 〃
: COPY -- ファイルとテーブルの間でデータをコピーする - 日々の記録 別館
: バイナリ形式 COPY 文の怪( binary 指定と二重引用符について) - StackOverflow : postgres copy command, binary file
- 〃
: How to export binary file with psql (without PGCOPY header)? - バイナリファイルの先頭バイトをカットする方法
- PortableApps.com : Git Portable 2.6.2 Development Test 1