要約:PostgreSQLの汎用ファイルアクセス関数を使い、文字コードUTF-8のデータベースで、日本語パスの日本語ファイルを読み込んでみました。ただし親フォルダはアスキー文字だけ。また文字コード変換が必要で、クエリは昨日のVirtualBox+仮想マシン+共有フォルダの方が簡単。(下記SQLのテキストはこちら
実行環境
• 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で読み込めます。場面に応じて使い分ければいいかな。