- ベストアンサー
文字化けします。
お世話になります。 ソケットでサーバとクライアントを接続しています。 コーディングの概略は次の通りです。 【クライアント】 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"EUC_JP")); out.println("かきくけこ"); System.out.println(in.readLine()); 【サーバ】 PrintWriter out = new PrintWriter(socket.getOutputStream(), true); BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream(),"Shift_JIS")); String inputLine; while ((inputLine = in.readLine()) != null) { System.out.println(inputLine); out.println(inputLine); //←これはクライアントでも文字化けしない。 String s1 = "あいうえお"; String u1 = new String(s1.getBytes("xxxxx"), "yyyyy"); out.println(u1); //←文字化けする。 } お伺いしたいのは文字コード変換についてです。 サーバ:RedhatLinux クライアント:Windowsでして、 サーバ側コーディングの String s1 = "あいうえお"; としている文字列を クライアント側の // 読み込んだデータを表示 System.out.println(in.readLine()); で表示したいのですが、文字が化けて(????←このようになります)困っています。 文字コード変換しなければいけないと思うのですが、 getBytesを使うのでしょうか? もしgetBytesを使うならどのように書けばいいのかがわかりません。 分かりにくい説明で申し訳ありませんが、 ご教授ください。宜しくお願いします。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
> Windows上でコーディングした、 > String str = "あああ"; > System.out.println(str); > をLinux上にFtpでアップして > 実行すると当然文字化けしますが、 > どのようにコード変換すればよいのでしょうか? えーっと、「Windows上でコーディング・コンパイルしたものをLinux上で実行すると文字化けする」ということですよね? 多分Windows上ではShift_JISで保存されてますよね。 で、LinuxではEUC_JPであると・・・ おそらく、ソース中でコード変換をするのではなく、ソースをEUC_JPで保存しなくてはならないのだと思います。 (前に一度ハマりました) そのときはEclipseを使って開発していたので、文字コードをEUC_JPと指定したらうまくいきました。 確か、Javaソースは実行環境と同じ文字コードで保存しなくてはいけないと記憶しています。 また、EUC_JPで保存したソースをWindows上で手動でコンパイルする場合、 javac -encoding EUC_JP xxx.java と文字コードを指定しなくてはならないようです。 (Eclipseはそこまでやってくれるようです) また外していたら申し訳ありません。
その他の回答 (6)
- deadlock
- ベストアンサー率67% (59/87)
私の回答も誤解がありそうな部分があったので補足です。 >(1)#1の >>String str = "あああ"; >>System.out.println(str); >これは文字化けしないはずです。 ソースを文字コード変換なしでアップロードして、サーバ上でコンパイルしているのであれば、kei5989さんの仰る通り文字コードを指定する必要があります。 コーディング-実行環境間で文字コードが一致する必要はありませんが、コーディング-コンパイルでは一致させる必要があります。 コンパイル済みのクラスファイル(やjar, warなど)をアップロードしているのであれば、文字化けは起こりません。
お礼
文字コードについていまいち理解していませんでしたがたいへん勉強になりました。ありがとうございました。
- deadlock
- ベストアンサー率67% (59/87)
はじめまして。まずは本題から。#1のk5989さんの回答にある、 new String(s1.getBytes("xxxxx"), "yyyyy") は削除してみましたか?多分これが原因です。 たとえば、UnicodeをShift_JISとして変換したバイト列を、EUCのバイト列のつもりで読み込めば、当然文字化けします。 Writerに書き込まれる前に、u1の時点で文字化けしているはずです。 s1を直接送信してみてください。 いくつか見当たるものを… (1)#1の >String str = "あああ"; >System.out.println(str); これは文字化けしないはずです。文字リテラルは、コンパイルする時点でUnicode変換されます。おそらく標準出力を見ているツール(Telnet端末?)の文字コード設定が間違っているのでしょう。 (2)サーバサイドの環境設定。 サーバでJavaのプロセスを動かしている環境設定では、文字コードはEUCですか?ログインシェルや、プロセスの起動シェルで文字コードが変更されている可能性がありますので、文字化けがおきたときはこの辺も確認してみてください。 (3)コード変換の場所をサーバ/クライアントどちらかに統一してください。 両方で変換をかけず、サーバのみ・クライアントのみで変換を書けるようにしたほうが分かりやすいでしょう。修正/コンパイルなどが楽な方で試してみてはどうでしょう。 また、両方で変換をかけるのであれば、通信に使うWriter/Reader生成時にはすべて同じエンコードを指定すると(2)であげたような環境設定に影響されずにすみます。
>コンパイルして、実行しましたが >例外が出てしまいました。 あ、ひょっとしてコンパイルのときにエラーになりましたか? すいません。encodeは例外を発生させるので、この処理はtry内で実行する必要があります。書き忘れてました。
補足
あ、すみません。 キャラクタセット名が悪かったみたいでした。 キャラクタセット名をAPIに記載しているものを一通りためしたのですが、うまくいきませんでした。 何か使い方が間違っているのでしょうか?
とりあえず原因究明は脇に置いて、テキストを指定のキャラクタセットを使った形にエンコーディングする基本についてだけ。こんな感じでできると思います。 // import java.nio.*; // import java.nio.charset.*; が必要。 Charset iso = Charset.forName(キャラクタセット名); CharsetEncoder encoder = iso.newEncoder(); CharBuffer cbuf = CharBuffer.wrap(変換前テキスト.toCharArray()); ByteBuffer bbuf = encoder.encode(cbuf); String 変換済みテキスト = new String(bbuf.array()); データが破損しているとかでなく、本当にキャラクタセットが異なるために文字化けが起こっているのであれば、これでいろいろと変換して文字化けが解消するか試してみてはいかがでしょうか。
補足
レスありがとうございます。 Windows上で String s1 = "あああ"; Charset iso = Charset.forName("EUC_JP"); CharsetEncoder encoder = iso.newEncoder(); CharBuffer cbuf = CharBuffer.wrap(s1.toCharArray()); ByteBuffer bbuf = encoder.encode(cbuf); String s2 = new String(bbuf.array()); System.out.println(s2); とコーディングして、 これをLinux上にアップロードして、 コンパイルして、実行しましたが 例外が出てしまいました。 使用方法が間違っているのでしょうか?
- kei5989
- ベストアンサー率40% (11/27)
すみません、さっきの回答、間違ってますね。 よく見たら、サーバ/クライアントともにBufferedReader(受信側)ですね。 後半は読み捨ててください(汗)。 となると、原因がよくわからなくなってきますね・・・ inputLineもu1もStringなのに、u1だけ文字化けするなんて・・・ ちなみに、System.out.println(inputLine);では文字化けせずに表示されてますか? また、String u1 = new String(s1.getBytes("xxxxx"), "yyyyy");の変わりにSystem.out.println(s1);とするとどのように表示されますか?
- kei5989
- ベストアンサー率40% (11/27)
こんばんは、mikimiki777さん。 ぱっと見ただけなので、外していたらゴメンナサイ・・・ まず、Java上のStringはすべてUnicodeでエンコードされていることは理解しておられますか? それを踏まえて見てみると、 >String s1 = "あいうえお"; >String u1 = new String(s1.getBytes("xxxxx"), "yyyyy"); s1はUnicodeです。 u1もUnicodeなのですが、「new String(s1.getBytes("xxxxx"), "yyyyy")」は何をしておられるのでしょうか? s1がすでにUnicodeである以上、ここでのコード変換は意味がないように思います。 String#getBytes(enc)メソッドはStringオブジェクトを文字コードをencとしてbyteの配列に変換するものです。 String(b, enc)コンストラクタはbyteの配列bを文字コードencとして解釈し、新たにStringオブジェクトを作るものです。 あくまで、Stringオブジェクトの中身はUnicodeであることを理解してください。 で、おそらく根本の原因はそこではないのですよね・・・ 私はソケットの経験はない上にソースも完全なものとは思えないので、憶測でしか言えませんが、クライアントとサーバで文字コードの指定(EUC_JPとShift_JIS)が異なっているのはよいのでしょうか? 私の理解では、 サーバでUnicodeからEUC_JPに変換して送信 ↓ クライアントでEUC_JPとして受信、Unicodeに変換してStringオブジェクトへ だと思うのですが・・・ ちょっとこれは本当に自信がありません。 外していたら申し訳ありません。
補足
基本的なことを再度お伺いします。 Windows上でコーディングした、 String str = "あああ"; System.out.println(str); をLinux上にFtpでアップして 実行すると当然文字化けしますが、 どのようにコード変換すればよいのでしょうか? 基本的なことですみません。
お礼
ありがとうございました。 文字コード指定とかで対応できそうです。 丁寧なご指導ありがとうございました。