subprocess.Popenを利用したJavaへの日本語のパラメータの渡し方を純粋なPythonと同様に行いたい

917 views
Skip to first unread message

shinriyo

unread,
May 25, 2014, 7:58:43 AM5/25/14
to djan...@googlegroups.com
お世話になっています。杉田と申します。

まず、環境は
---
Python 2.7.5
Django 1.6
Java "1.6.0_45"
--
で行っています。

Djangoを利用してDjangoから、あるJavaプログラム(java_program.class)をコールしています。
Javaをコールする方法として「subprocess.Popen」を利用し、
パラメータも同時に渡しております。

コードのニュアンスを失わない程度に実際とは変数名などを変えてますが、
実際のスニペットは以下のような感じです。

---
class_path = '/path/to'
sys.path.insert(0, java_file_path)

java_file = 'java_program'
class_path = '-cp ' + java_file_path
cmd = "java {0} {1} {2}".format(class_path, java_file, japanese)
import subprocess
proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
proc.wait()
---

japaneseには「クライアントから渡ってきた文字」が入っています。
sys.path.insertとjavaコマンドに-cpを使うことで、
うまく呼び出せました。

”英語”ではうまくJavaは動作していますが、
”日本語”を渡すとJavaにはわたっているものの失敗してしまいます。

しかし、同じようなコードを"Djangoを使わず"に"Pythonだけ"で行った場合には、
日本語を利用しても特に問題はありませんでした。
ですので、おそらくJava側には問題は無いと思います。

PythonもJavaも共にファイル自体は「UTF-8のBOMなし」です。

Djangoを介すとどうしても失敗してしまいます。

当然ですが、
#!/usr/bin/env python
# -*- coding: utf-8 -*-
は付与しておりますし、

トライ&エラーを行い、
sys.stdout = codecs.getwriter('utf-8')(sys.stdout)
locale.getpreferredencoding = lambda: 'UTF-8'
locale.setlocale(locale.LC_ALL, '')
のようなコードを埋め込んでもだめでした。

単純にPythonだけを使った時と同様の処理をDjangoで行うことをしたいのですが、
どうすればよろしいでしょうか?

何卒、よろしくお願いします。

tokibito

unread,
May 25, 2014, 12:57:24 PM5/25/14
to djan...@googlegroups.com
岡野です。

エラー内容が書かれていないですが、エンコードまわりの問題ですかね?

sys.pathはPythonのモジュールの検索に使われるものなので、
Javaのプログラムを実行する際には設定不要です。

OSの種類とバージョンが書かれていませんが、Linux(Debian/UbuntuやRedHat/CentOS)と仮定します。
Popenで日本語の文字列を投げる場合、UTF-8でエンコードする必要があります(試してないですがLANG環境変数によって動作が変わるかも)

また、subprocessモジュールで実行して標準出力を受け取る場合、stdout.read()の結果はUTF-8でデコードする必要があります。

サンプルコード一式をbitbucketに置いときました。java6, java7で動作確認済み。

以上

2014年5月25日日曜日 20時58分43秒 UTC+9 shinriyo:

杉田臣輔

unread,
May 25, 2014, 10:08:50 PM5/25/14
to djan...@googlegroups.com
岡野さん

御返信有難うございます。

ご指摘の通り、先程のプログラムに抜けておりましたが、日本語の文字列に対して、
.encode('utf-8')にてUTF-8でエンコードしております。

日本語を、.encode('utf-8')をしておかないと、
"'ascii' codec can't encode characters in position 0-11: ordinal not in range(128)"
になります。


Javaに渡す前のPythonの時点での実際の日本語の格納されている変数を、
テキストに書き込んでみましたが、
日本語がそのまま表示されており、正常と思われます。

しかし、Pythonから来たJavaのパラメータ「args[0]」をテキストに出力してみると、

????????????????????????????????????

のようにハテナの文字だけが出力されていました。

Subprocessのコマンド内に、Javaのコマンドのオプションとして
-Dfile.encoding=UTF-8
を追加してみましたが、

������������������������������������

白抜きのハテナの黒のダイヤのような文字に化けて出力されました。

Javaをコンパイルする際には、
-encoding UTF-8
のオプションをつけています。

>OSの種類とバージョンが書かれていませんが

これらは、このようになっています。
Linux version 2.6.32-431.3.1.el6.x86_64
CentOS release 6.5 (Final)

sys.pathはPythonのモジュールの検索に使われるものなので
>Javaのプログラムを実行する際には設定不要です。

有難うございます。
1.3.7から1.6にアップデートした経緯があったのですが、
1.3.7のときはsys.path.insertをしていないと出来なかった気がしますが、
今の1.6のバージョンで試しに外してみると、
今はなくても他のパスのJavaをコールすることは大丈夫でした。





2014年5月26日 1:57 tokibito <toki...@gmail.com>:

--
--
----------------- http://djangoproject.jp/ -----------------
You received this message because you are subscribed to the Google Groups "django-ja" group.
To post to this group, send email to djan...@googlegroups.com
To unsubscribe from this group, send email to django-ja-...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/django-ja
---
このメールは Google グループのグループ「django-ja」のトピックを登録しているユーザーに送られています。
このトピックの登録を解除するには https://groups.google.com/d/topic/django-ja/l6W5y1ACIQo/unsubscribe にアクセスしてください。
このグループを退会し、グループのすべてのトピックの登録を解除するには django-ja+...@googlegroups.com にメールを送信してください。
その他のオプションについては https://groups.google.com/d/optout にアクセスしてください。

tokibito

unread,
May 26, 2014, 12:28:03 AM5/26/14
to djan...@googlegroups.com
岡野です。

文字化けしている状態だとすると、パイプで引数を渡す際にやっぱり環境変数か何かの影響で壊れてしまってる可能性が高いですね。

Popenの引数にshell=Trueを指定している理由は何かありますか?

shell=Trueだと/bin/sh経由で実行されることになるので、環境変数が変わる可能性があります。Falseにしてどうなるか試してみてください。

Djangoの実行方法はどうしていますか? runserver, mod_wsgi, gunicornなど、実行方法によって環境変数が変わる可能性があります。
exportコマンドで "LANG=ja_JP.UTF-8" を設定するなどの対応が必要になるかもしれません。

2014年5月26日月曜日 11時08分50秒 UTC+9 shinriyo:

杉田臣輔

unread,
May 26, 2014, 10:25:20 AM5/26/14
to djan...@googlegroups.com
岡野さん

返信ありがとうございます。

>Popenの引数にshell=Trueを指定している理由は何かありますか?
>shell=Trueだと/bin/sh経由で実行されることになるので、環境変数が変わる可能性があります。Falseにしてどうなるか試してみてください。

指定している理由は得にありませんでしたが、試しに外して実行してみると、
エラーになりました。

/var/log/httpd/error20140526.logでのログはこちらです。
[error]   File "/usr/local/Python2.7.5/lib/python2.7/subprocess.py", line 711, in __init__
[error]     errread, errwrite)
[error]   File "/usr/local/Python2.7.5/lib/python2.7/subprocess.py", line 1308, in _execute_child
[error]     raise child_exception
[error] OSError: [Errno 2] No such file or directory

>Djangoの実行方法はどうしていますか? runserver, mod_wsgi, gunicornなど、実行方法によって環境変数が変わる可能性があります。

実行環境はmod_wsgiで行っています。

>exportコマンドで "LANG=ja_JP.UTF-8" を設定するなどの対応が必要になるかもしれません。

shのLANGはenvコマンドで確認したところ、LANG=ja_JP.UTF-8となっておりました。
環境変数だけでなく、システム側も/etc/sysconfig/i18nにてLANG="ja_JP.UTF-8"にしている状態です。

何卒、よろしくお願いします。




2014年5月26日 13:28 tokibito <toki...@gmail.com>:

tokibito

unread,
May 26, 2014, 2:27:20 PM5/26/14
to djan...@googlegroups.com
岡野です。

>[error] OSError: [Errno 2] No such file or directory

shell=Falseの場合は実行コマンドとパラメータをリスト(タプル)で渡す必要があるので、最初のコメントで示したサンプルコードを参考にしてみてください(もしくはサンプルコードを該当の環境で動かしてみてください)

modwsgi経由で動かしている場合、os.environのLANGはどうなりますか?
もし、ja_JP.UTF-8になっていないならwsgiファイルに

import os
os.environ['LANG'] = 'ja_JP.UTF-8'

を先頭に入れてみてください。Djangoのハンドラに入る前に環境変数を変更できます。

2014年5月26日月曜日 23時25分20秒 UTC+9 shinriyo:

杉田臣輔

unread,
May 26, 2014, 11:58:10 PM5/26/14
to djan...@googlegroups.com
岡野さん

ありがとうございます。

shell=Falseにすることと、パラメータをリストにすることによって無事に動作いたしました。
なかなか解決できなかったので、本当にありがとうございました。



2014年5月27日 3:27 tokibito <toki...@gmail.com>:
Reply all
Reply to author
Forward
0 new messages