質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
Android Wear

Android Wearとは、Googleが発表した腕時計型ウェアラブルデバイス(スマートウォッチ)向けのプラットフォームです。GoogleのAndroid OSをベースにしており、情報の入手・管理などを行うことができます。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

Q&A

解決済

1回答

716閲覧

Android、RetrofitでSHIT-JISのCSVファイルをダウンロードすると、どうしても文字化けする

退会済みユーザー

退会済みユーザー

総合スコア0

Android Wear

Android Wearとは、Googleが発表した腕時計型ウェアラブルデバイス(スマートウォッチ)向けのプラットフォームです。GoogleのAndroid OSをベースにしており、情報の入手・管理などを行うことができます。

Kotlin

Kotlinは、ジェットブレインズ社のアンドリー・ブレスラフ、ドミトリー・ジェメロフが開発した、 静的型付けのオブジェクト指向プログラミング言語です。

0グッド

0クリップ

投稿2023/07/07 08:40

実現したいこと

Androidで、リモートにあるSHIFT-JISのCSVファイルをHTTPで取得し、それをカンマ区切りで分解してroom(SQLite)にINSERTしようとしていますが、どうやっても文字化けします。
HTTP/GETでファイルを取得するのにretrofitを使っているのですが、どうもretrofitの中で文字化けしているように思えます。response bodyがもはや、SHIFT-JISでもUTF-8でもない、壊れたStringになっているような気がします。
retrofitは無理やりUTF-8にしようとしているのでしょうか?

発生している問題・エラーメッセージ

retrofitで受け取ったresponse bodyが文字化けしている。

該当のソースコード

build.gradel

plugins { id 'com.android.application' id 'org.jetbrains.kotlin.android' id "org.jetbrains.kotlin.kapt" } android { namespace 'jp.hogehoge.hogeapp' compileSdk 33 defaultConfig { applicationId "jp.hogehoge.hogeapp" minSdk 28 targetSdk 33 versionCode 1 versionName "1.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // Room Schema export javaCompileOptions { annotationProcessorOptions { arguments += [ "room.schemaLocation":"$projectDir/schemas".toString(), "room.incremental":"true", "room.expandProjection":"true"] } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { sourceCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_17 } kotlinOptions { jvmTarget = '17' } buildFeatures { viewBinding true } packagingOptions { resources { excludes += ['META-INF/LICENSE.md', 'META-INF/LICENSE-notice.md'] } } testOptions { unitTests { includeAndroidResources = true // robolectric } packagingOptions { jniLibs { useLegacyPackaging = true // espresso, mockk } } } } dependencies { implementation 'androidx.core:core-ktx:1.10.1' implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'com.google.android.material:material:1.9.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.preference:preference:1.2.0' // Activity KTX implementation 'androidx.activity:activity-ktx:1.7.2' // Barcode Library implementation files('libs/scan_sdk.jar') // Coroutine implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1' // Lifecycle components def lifecycle_version = '2.6.1' implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${lifecycle_version}" implementation "androidx.lifecycle:lifecycle-livedata-ktx:${lifecycle_version}" implementation "androidx.lifecycle:lifecycle-common-java8:${lifecycle_version}" implementation "androidx.lifecycle:lifecycle-extensions:2.2.0" // Room def room_version = '2.5.2' kapt "androidx.room:room-compiler:$room_version" implementation "androidx.room:room-ktx:$room_version" // Commons validator implementation 'commons-validator:commons-validator:1.7' // Retrofit def retrofit_version = "2.9.0" implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.11' implementation 'com.squareup.retrofit2:converter-scalars:2.9.0' // openCSV implementation 'com.opencsv:opencsv:5.7.1' }

NetworkService.kt

interface NetworkService { @GET suspend fun csvDownload( @Url url:String ): String }

NetworkRepository.kt

class NetworkRepository(val downloadUrl: String, val uploadUrl: String, timeout: Long) { private var service: NetworkService init { val logging = HttpLoggingInterceptor() logging.setLevel(HttpLoggingInterceptor.Level.BASIC) val client = OkHttpClient.Builder() .readTimeout(timeout, TimeUnit.SECONDS) .connectTimeout(timeout, TimeUnit.SECONDS) .addInterceptor(logging) .build() service = Retrofit.Builder() .baseUrl(downloadUrl) .client(client) .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(NetworkService::class.java) } suspend fun download(): Unit { val url = "http://www.hoge.jp/hoge.csv" val response = service.csvDownload(url) // ★ この時点でresponseがSHIT-JISでもUTF-8でもない、壊れたString ByteArrayInputStream(response.toByteArray()).use { bis -> BufferedReader(InputStreamReader(bis, Charset.forName("SHIFT-JIS"))).use { bufr -> CSVReader(bufr).use { reader -> val csvList = CsvToBeanBuilder<MyCsv>(reader) .withType(HtYakuCsv::class.java) .withIgnoreLeadingWhiteSpace(true) .build() .parse() // ★なのでいくら頑張っても文字化けしている } } } } return result } }

試したこと

service = Retrofit.Builder() .addConverterFactory(ScalarsConverterFactory.create())

retrofitのこのConverterを色々変えてみました、変わらず、

interface NetworkService { @GET suspend fun csvDownload( @Url url:String ): String }

このの戻り値をString、Respose<ResponseBody>、色々変えてみましたが、変わらず

補足情報(FW/ツールのバージョンなど)

Android11(R)
kotlin
retrofit 2.9.0

ここにより詳細な情報を記載してください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

可能性としては、つぎのどちらかだと思います。

  1. Retrofitはレスポンスのキャラクタセットを正しく認識できるのだが、サーバが返すレスポンスのキャラクタセット指定がShift_JISになっていないので、RetrofitもShift_JISだと認識できない。
  2. Retrofitはレスポンスのキャラクタセットを認識していないので、Shift_JISのテキストも素通ししてしまい、UTF-8前提のアプリケーションで正しく処理できない。

たぶん2.ではないかと思います。

その場合、(Retrofitを使ったことがないので間違っているかもしれませんが) Retrofit自身はOkHttpのラッパなので、OkHttpClientでinterceptorを使ってリクエストやレスポンスに細工することができるようです。ここでレスポンスを見てShift_JISだったらUTF-8に変換してからアプリケーションに渡してやればなんとかならないでしょうか。

追記

一方、@GETcsvDownload()Stringを返させるということもできないのではないかと思いました。retrofitはレスポンスのキャラクタセットを認識していないと思われるため、勝手にStringになってくれることはないと思います。

このようにさせたいのであれば、ResponseBodyの内容をByteArrayとして取得した上で、toString()でShift_JISのバイト列からStringに変換する必要があると思います。

投稿2023/07/07 09:23

編集2023/07/08 08:07
ikedas

総合スコア4400

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2023/07/10 02:08

ご指摘の通りです。 ``` interface NetworkService { @GET suspend fun csvDownload( @Url url:String ): Response<ResponseBody> } ``` ``` class NetworkRepository(val downloadUrl: String, val uploadUrl: String, timeout: Long) { private var service: NetworkService init { // TODO SharedPreferenceの変更が随時反映されない // ロギング val logging = HttpLoggingInterceptor() logging.setLevel(HttpLoggingInterceptor.Level.BASIC) val client = OkHttpClient.Builder() .readTimeout(timeout, TimeUnit.SECONDS) .connectTimeout(timeout, TimeUnit.SECONDS) .addInterceptor(logging) .build() service = Retrofit.Builder() .baseUrl(downloadUrl) .client(client) .addConverterFactory(ScalarsConverterFactory.create()) .build() .create(NetworkService::class.java) } suspend fun download: Unit { val result = mutableListOf<HtYaku>() val url = "http://hogehoge.jp/hoge.csv" val response = service.csvDownload(url) response.body()?.byteStream().use { bst -> BufferedReader(InputStreamReader(bst, Charset.forName("SHIFT-JIS"))).use { bufr -> CSVReader(bufr).use { reader -> val csvList = CsvToBeanBuilder<MyCsv>(reader) .withType(MyCsv::class.java) .withIgnoreLeadingWhiteSpace(true) .build() .parse() ・・・・ } } } return result } ``` に変えたらうまくいきました。 色々、試行錯誤じているときに、Response<ResponseBody> も試したはずだと思っていたんですが・・・ 今やると、この方法でうまくいきました。
ikedas

2023/07/10 02:52

そのうまくいったコードを自己回答として投稿しておかれてはどうでしょうか。他の誰かの参考になりますから。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問