要約:PostgreSQLの汎用ファイルアクセス関数を使い、文字コードUTF-8のデータベースで、日本語パスの日本語ファイルを読み込んでみました。ただし親フォルダはアスキー文字だけ。また文字コード変換が必要で、クエリは昨日のVirtualBox+仮想マシン+共有フォルダの方が簡単。(下記SQLのテキストはこちら)
Contents
実行環境
• Windows7 32bit + PostgreSQL Portable 9.4.1• データベースの文字コード …UTF-8• データベースのロケール …CまたはJapanese_Japan.932で確認• PostgreSQLへの接続ユーザ …postgres(スーパーユーザ)• client_encoding…UNICODE(pgAdminクエリツール起動時のデフォルト)
PostgreSQLの汎用ファイルアクセス関数が読み込めるデータフォルダ直下に、下のようにテスト用フォルダと4つのファイルを作成。中身は同じ日本語の短文で、シフトJISとUTF-8別々に用意しました。
PGDATA
┣ base
┣ global
┣ pg_clog
┣ .....
┗ test
┣ New Text Document SJIS.txt
┣ New Text Document UTF8.txt
┣ 新しいテキスト ドキュメント SJIS.txt
┗ 新しいテキスト ドキュメント UTF8.txt
↓client_encodingは変更せず、pgAdminクエリツール起動時のUNICODEのまま。
SQLの例
最初に完成形から。pg_ls_dir関数でtestフォルダ下の4つのファイル名を取得し、そのままpg_stat_file関数に渡してサイズ取得、同様にpg_read_binary_file関数でバイナリとして読み込みます。ファイル名の文字コードがシフトJISになってるので、表示用にconvert_from関数で変換。またファイル内容のバイナリを文字コードに合わせて変換。その際、ファイル名からsubstring関数で文字コードを切り出し。
SELECT fname_sjis, size, bin,
convert_from(bin, substring(fname_sjis, '((SJIS)|(UTF8))'))
FROM pg_ls_dir('test') AS fname,
concat('test/', fname),
convert_from(fname :: bytea, 'SJIS') fname_sjis,
pg_stat_file(concat),
pg_read_binary_file(concat) bin;
↓ ファイル名の変換をしない場合。PostgreSQL内部ではファイルを認識できていますが、日本語(正確には非アスキー文字)を含むファイル名は文字コードが違うため空文字に。client_encoding設定によっては、空文字にならずエラーが起きるかも。
SELECT fname, size, bin
FROM pg_ls_dir('test') AS fname,
concat('test/', fname),
pg_stat_file(concat),
pg_read_binary_file(concat) bin;
↓ ファイル名がアスキー文字だけで、中身がUTF-8テキストならpg_read_file関数で単純に読み込めます。一方ファイルパスに非アスキー文字があるとNo such file or directoryと見つからないエラー。
結局、Windows上で日本語など非アスキー文字を含むファイル・フォルダを直接指定して汎用ファイルアクセス関数に渡す方法は、いろいろ試したけどUTF-8のデータベースでは見つからず。今回のtestのように親フォルダをアスキー文字だけで作りpg_ls_dir関数に渡せばいいけど、できれば直接指定したい…。
SQL_ASCIIのデータベースなら、日本語パスのファイルを直接指定可
上の実行環境と別に、文字コードSQL_ASCIIのデータベースを作って試したら、日本語を含むファイル名を直接指定してpg_read_file関数で読み込めました。↓ 中身がシフトJISなら文字コード変換不要。でもUTF-8のファイルは、pg_read_fileでも、pg_read_binary_file経由で変換しても表示できず。
ファイル・フォルダ名だけ必要とか、中身がシフトJISだけと分かってる場合にはSQL_ASCIIでも間に合うかもですが、そもそもデータベースを作る時に ↓ の警告が出るし、ドキュメントにも「多くの場合、ASCIIではない環境で作業する場合はSQL_ASCIIの設定を使用するのは、賢いことではありません」(9.4第22章 多言語対応)とあるので、実際使うのは無理そう。
VirtualBox仮想マシンとの比較
昨日の再掲になりますが ↓ こんな感じで日本語パスを含むWindowsホスト側のファイル・フォルダへ簡単に、文字コード変換せずアクセス可能。データベースの文字コードはUTF-8。ホストとゲストをつなぐVirtualBoxの共有フォルダが、Windowsのファイル名をうまく処理してるのかも?
上の方法の短所は、環境構築の手間と、共有フォルダを変更する場合に仮想マシン再起動が必要なこと。ホスト側にある特定のフォルダを手軽にPostgreSQLで読み込みたくとも、共有フォルダにコピーするか、そこに共有フォルダを設定して仮想マシン再起動が必要。
一方、今回のWindows上でのみ行う方法はクエリが面倒だけど、対象フォルダへのシンボリックリンクを一時的に作ってPGDATA下に置けば、すぐPostgreSQLで読み込めます。場面に応じて使い分ければいいかな。