hsurich

hsurich

coder
github
telegram
x
email
steam

JDK中のDataOutputStream.writeBytesメソッドで中国語を渡すと文字化けします。

java プロジェクトでは、パッケージ化された POST リクエストのメソッドがあります。

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;
import java.util.Map.Entry;

public class FormDataPostRequest {

    public static String sendPostFormData(String url, Map<String, String> headerParams, String text) {
        String result = ""; // 結果を返す
        BufferedReader in = null; // 応答入力ストリームを読み取る

        try {
            // 接続を作成する
            URL apiUrl = new URL(url);
            HttpURLConnection connection = (HttpURLConnection) apiUrl.openConnection();
            connection.setDoOutput(true);
            connection.setDoInput(true);
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setInstanceFollowRedirects(true);
            connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + "*****"); // boundaryを設定する
            if (headerParams != null) {
                for (Entry<String, String> entry : headerParams.entrySet()) {
                    connection.setRequestProperty(entry.getKey(), entry.getValue());
                }
            }
            connection.connect();

            // POSTリクエストを送信する(文字列パラメータを含む)
            DataOutputStream out = new DataOutputStream(connection.getOutputStream());
            // 文字列パラメータを追加する
            out.writeBytes("--*****\r\n");
            out.writeBytes("Content-Disposition: form-data; name=\"text\"\r\n\r\n");
            out.write(text.getBytes("UTF-8"));
            out.writeBytes("\r\n");
            out.writeBytes("--*****--\r\n");
            out.flush();
            out.close();

            // 応答を読み取る
            // URLの応答を読み取るためにBufferedReader入力ストリームを定義し、エンコーディングを設定する
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
            String line;
            // 返された内容を読み取る
            while ((line = in.readLine()) != null) {
                result += line;
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("HTTPリクエストメソッドの内部問題");
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return result;
    }
}

元々は問題ありませんが、後続の使用中に、パラメータの値が中国語の場合、受信側で文字化けが発生することがわかりました。コードを確認すると、問題がこの行で発生していることがわかります。

out.writeBytes(text + "\r\n");

writeBytesのソースコードを確認すると、文字列 s の各文字が byte 型に強制変換され、高い 8 ビットが破棄されます。例外が発生しない場合、カウンタwrittensの長さだけ増加します。

public final void writeBytes(String s) throws IOException {
    int len = s.length();
    for (int i = 0 ; i < len ; i++) {
        out.write((byte)s.charAt(i));
    }
    incCount(len);
}

中国語の文字は 16 ビットであり、byte 型は 8 ビットであるため、文字が中国語の場合、切り捨てられて文字化けが発生します。いくつかのログを追加して、変換後の byte 配列を確認してみましょう。

public final void writeBytes(String s) throws IOException {
    int len = s.length();
    for (int i = 0 ; i < len ; i++) {
        char c = s.charAt(i);
        byte b = (byte) c;
        System.out.println("文字:" + c + " 変換後のbyte配列:" + b);
        out.write(b);
    }
    incCount(len);
}

最終的に、中国語の文字が強制変換されると、8 ビットが失われ、文字化けが発生することがわかります。したがって、文字列を byte 配列に変換してから出力ストリームに書き込む解決策を採用します。

// POSTリクエストを送信する(文字列パラメータを含む)
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
// 文字列パラメータを追加する
out.writeBytes("--*****\r\n");
out.writeBytes("Content-Disposition: form-data; name=\"text\"\r\n\r\n");
out.write(text.getBytes("UTF-8"));
out.writeBytes("\r\n");
out.writeBytes("--*****--\r\n");
out.flush();
out.close();
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。