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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

2回答

3060閲覧

Android Studio アプリ内で読み込んだCSVのデータが大きすぎてアプリがダウンしてしまう

sekaikan_ozaki

総合スコア65

Java

Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

Android

Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

1クリップ

投稿2019/05/24 05:19

編集2019/05/24 06:06

PCスペック
Windows7 64bit
メモリ 8GB
プロセッサ Intel Core i7-3610

エミュレータ(Nexus S API 28)
Android Studio 3.4

Android Studioで、開発しているアプリで、途中CSVファイルを読み込む(そのデータが必要なため)箇所があります。

しかし、取り扱うデータが入ったCSVファイルのサイズが大きすぎるせいか(約40.0MBで、行のセルが18万個、列は13個)、アプリが立ちあがったと思ったら、すぐにダウンして「アプリが繰り返し停止しています」というようなメッセージが出て、実行が自動で停止してしまいます。

アプリがすぐ落ちる原因は、やはりCSVファイルのサイズのせいでしょうか?
それともこれ以外になにか別に原因がある可能性はあるのかも気になります。。

どうしても、扱いたいデータなので、なんとか読み込んでアプリが正しく動くようにしたいのですが、解決方法はありませんでしょうか・・??

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

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

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

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

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

jimbe

2019/05/24 11:37

csv ファイルが巨大な所為と仮定しまして, 試しに小さい csv (元のデータの前半半分など)で試してみてはいかがでしょうか. 半分でだめなら1/4, 1/4でだめなら1/8としてみる等で, もし 100 件でも発生するようでしたら, csv が原因では無いかもしれません.
sekaikan_ozaki

2019/05/27 01:37 編集

返信が遅れてしまい申し訳ございません。 assetsにおいたCSVファイルを見ると、上の方に、 The files is too large: 41.93MB. Showing a read-only preview of the first 2.56MB.(訳:ファイルが大きすぎます:41.93メガバイト。 最初の2.56MBの読み取り専用プレビューを表示しています。) と表示されていました。 assetsに入れたCSVファイルを見てみると、6616行までしか表示されていませんでしたので、試しに6616行までのCSVファイルを作って、アプリを実行してみると、正常に動作し、自分のソースコードの通りに、中のプログラム(前回の質問のアプリの続き)も動いてくれました。 念のため、6617行のCSVもやってみると上手くいきました さらに、3行のみにしたCSV、10000行にしたCSVでも、入力した文字に対応する列の文字を画面に表示させることができました。(どのCSVも列は14列あります。入力する文字の1列+対応する「気温」や「電車の本数」などのその他13列) このことから、CSVそのものに原因があることはないと考えられます。 また、他者様のアンサーで、 readCSV()の中の、 catch (IOException e) { e.printStackTrace(); } を catch (Exception e) { } に書き換えたところ、元々扱いたいファイル(41.93MBで18万行、13列)をassetsに入れた状態でも、アプリが正常に立ち上がり、1~14000行目くらいまでは読み込みがうまくいってるのか、入力した文字に対応する情報を表示することが出来ていました。 しかし、15000行以降になると、正しい文字を入力しても、「入力した文字が間違っています」と表示され、ちゃんと読み込みが出来ていない状態となっています。 やはりCSVのデータサイズが問題ということでどうしようもないことなのでしょうか? また、40MB程度のファイルというのは、読み込みが難しいくらいのサイズなのでしょうか。 その場合、大規模なデータを利用するタイプのAndroidアプリは、何か別の方法(CSV以外などでも)を使って、膨大なデータを読み取っているのでしょうか?
jimbe

2019/05/27 02:02 編集

> The files is too large: はそのプレビューのプログラムにとって大きいと言っているのではないでしょうか. > catch (Exception e) { } としたら正常に…というのは少し違うと思います. 単に例外を全て無視しているだけなので, 問題は解決していません. その 14000~15000行付近で異常が発生しているのでしょう. 「大量のデータをリスト表示する」という点からしますと, データベースに入れて CursorLoader を用いるアダプタによってリスト表示するのが一般的かと思います. データベースに入れる元データは, 圧縮しておくことを基本として, (通信機能があれば)サーバから取り込むでしょう.
jimbe

2019/05/27 02:06

catch (Exception e) {} の中に e.printStackTrace(); を入れては如何でしょう. 何か表示されるかもしれません.
sekaikan_ozaki

2019/05/27 02:49 編集

早速のご返信ありがとうございます! e.printStackTrace();を加えても、特に表示はされないですね。。。(EventLogに表示なし) しかし、アプリは問題なく立ちあがって、文字を入力することができます。 >14000~15000行付近で異常が発生しているのでしょう. CSVファイルを開いて、この付近を注意深く見てみると、14576行目のBのデータが歯抜けになっていました。 試しに、B列の情報をカテゴリで先に指定しておいて、14576行目のA列の文字と正しい文字を入力したところ、アプリがダウンしました。 さらに、14576行目以降で、A列と正しい文字を入力しても、「入力した文字が間違っています」と表示されました。 このことから、CSVのデータが歯抜けになっていると、CSV自体を読み込むことはできるが、↓の1個目のif文のように歯抜けになっているセルの情報はgetできないので、そこでエラーが起きて、アプリがダウンしてしまうということだと解釈しました。 //入力された文字(時刻)と適合する時刻を探すメソッド public void match(String text){ String time; String temp = ""; String amount = ""; int find = -1; //時刻の情報を1番目から最後まで回す for(int i=0; i<timeList.size(); i++) { time = timeList.get(i); if (time.equals(text)) {//入力情報と一致したら temp = tempList.get(i); amount = amountList.get(i); find = 1; break; } } if(find == 1) { if(item == spinnerItems[1]) {//スピナーで選択した条件が「気温」だったら textView.setText(text + "の" + spinnerItems[1] + "は"+temp+"です"); }else if(item == spinnerItems[2]) {//条件が「電車の本数」だったら textView.setText(text + "の" + spinnerItems[2] + "は"+amount+"です"); } }else if(find == -1){ textView.setText("時刻が間違っています"); } } また、それ以降の行でいくら正しい文字を入力していたとしても、以前の行で歯抜けがあると、リストが歯抜けの部分で止まってしまっているので、14577行目以降の14列すべてデータを読み取れていなかったということではないでしょうか。 ↓例:3列の場合  /** * CSVの読み込み */ public void readCSV() { try { InputStream inputStream = getResources().getAssets().open("data1.csv"); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferReader = new BufferedReader(inputStreamReader); String line = ""; while ((line = bufferReader.readLine()) != null) { StringTokenizer stringTokenizer = new StringTokenizer(line, ","); timeList.add(stringTokenizer.nextToken());☆(歯抜けがあった箇所以降は、ここに読み取ろうとしたデータが入っていかないのでは?) tempList.add(stringTokenizer.nextToken());☆ amountList.add(stringTokenizer.nextToken());☆ } bufferReader.close(); } catch (IOException e) { e.printStackTrace(); } } また、歯抜けのデータはそれ以降のセルでも散見されます。。 以上から、歯抜けのセルに、適当にNULLなどを入れて、ただの空欄ではない様にする、エラーが起きなくする(その行の文字を入力したら、情報が入ってませんと表示してとりあえずなんとかやりくりしたい)のが次にやりたいこととなりました。 そこで、"CSV読み取りの時点"で、セルが空欄かどうかを判断し、空欄だった場合なんとか埋めるようにした方が良いと思ったのですが、何か良い方法はありませんでしょうか...??
sekaikan_ozaki

2019/05/27 02:53

> The files is too large: >はそのプレビューのプログラムにとって大きいと言っているのではないでしょうか. そうですね、こちらに関しては、そのように自分も思いました。
jimbe

2019/05/27 03:31

CSVファイルに不備が無い前提でお話をしていましたので, 不備が有っては前提が崩れますね^^; 対処は, 単に nextToken の結果を一時変数に入れて, if 文で空(null?)だったら~等と書くしかありません. また, 以前のご質問にも書きましたが, こういった場合は一行分をクラス化し, そのクラスの static メソッドとして「行を解析してオブジェクトを帰す」ように作ることかあります. 要は「行を解析し, 不備があったら補完する」メソッドとして別に切り出しておくと, CSV のフォーマットが変更されたりした場合もどこを直すのか分かり易いですし, どんな行が入力されたらどんなエラーになるかのテストがそのメソッドだけで確認できるようになります.
sekaikan_ozaki

2019/05/27 06:18

色々あってところどころ歯抜けがあるファイルでした。。前提を崩してしまい大変申し訳ございません。 試しに、「時刻」を入れて、「気温」or「電車の本数」を表示するアプリで、小規模な歯抜け状態のCSVファイルで、プログラムを組んでいる最中でございます。 用意したCSVは「気温」、「電車の本数」の列に歯抜けが全部で5個ある状態と仮定します。 時間,気温,電車の本数 1時,1度,1本 2時,2度,2本 3時,3度,3本 4時,4度,4本 5時,5度, 6時,,6本 7時,7度,7本 8時,8度,8本 9時,9度,9本 10時,10度,10本 11時,11度,11本 12時,12度,12本 13時,,13本 14時,14度,14本 15時,15度,15本 16時,16度,16本 17時,17度,17本 18時,18度,18本 19時,19度, 20時,20度,20本 21時,21度,21本 22時,,22本 23時,23度,23本 24時,24度,24本 CSVを読み取る部分と、入力された文字が一致するかを調べ、対応する文字を表示するメソッドの部分のコードは /** * CSVの読み込み */ public void readCSV() { try { //assetsからCSVファイルの読み込み InputStream inputStream = getResources().getAssets().open("data11.csv"); //1行ずつ読み込みを行うための変換 InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferReader = new BufferedReader(inputStreamReader); String line = ""; int count = 0; while (count <= 5) {//countが6以上で読み取り終了 line = bufferReader.readLine();//1行ずつデータを読み込み StringTokenizer stringTokenizer = new StringTokenizer(line, ",");//CSVがカンマ区切りなので、文字列をStringTokenizerでカンマ区切り if(stringTokenizer == null) { stringTokenizer.nextToken() = null; count ++; } timeList.add(stringTokenizer.nextToken()); tempList.add(stringTokenizer.nextToken()); amountList.add(stringTokenizer.nextToken()); } bufferReader.close(); } catch (Exception e) { e.printStackTrace(); } } //入力された文字(時刻)と適合する時刻を探すメソッド public void match(String text){ String time; String temp = ""; String amount = ""; int find = -1; //時刻の情報を1番目から最後まで回す for(int i=0; i<timeList.size(); i++) { time = timeList.get(i); if (time.equals(text)) {//入力情報と一致したら temp = tempList.get(i); amount = amountList.get(i); find = 1; break; } } if(find == 1) { if(temp == null){ textView.setText("情報が入っていませんでした"); }else if(amount == null){ textView.setText("情報が入っていませんでした"); } if(item == spinnerItems[1]) {//スピナーで選択した条件が「気温」だったら textView.setText(text + "の" + spinnerItems[1] + "は"+temp+"です"); }else if(item == spinnerItems[2]) {//条件が「電車の本数」だったら textView.setText(text + "の" + spinnerItems[2] + "は"+amount+"です"); } }else if(find == -1){ textView.setText("時刻が間違っています"); } } こんな感じですが、readCSV()の中の、 stringTokenizer.nextToken() = null;がエラー出てしまっていてプログラムを動かすことができない状態です。 やりたいこととしては、歯抜けの数が5個まではCSVを読み取るのを続ける(つまり、24時の行が過ぎれば、何もないセルの行になるので、それを6個目の歯抜けと認識するはず) そして、macthメソッドで、temp(気温)かamount(電車の本数)がnullの場合、"情報が入っていませんでした"と表示したいです。 >nextToken の結果を一時変数に入れて ここの部分がなかなか理解できておりません。。 stringTokenizer方は、セルの中身をトークンとして扱っていると思いますが、セルの中身が空だった場合は、nextToken?をどのように扱えば、そのあとのmatchメソッドにつながるのでしょうか。。
sekaikan_ozaki

2019/05/27 07:56 編集

オブジェクト指向については、1通り勉強してはいるのですが、いざコーディングするとなった際に、どのように部品化し、どのようにクラスをや、その中のフィールドなどを用意するかを事前に練っておくのがまだまだ慣れておらずアウトプットが全然できていない状態です。。(センスも必要なのか) いまの自分のコードを見ていると、MainActivityクラスだけですべての処理を記述しているので、コードが長くなるにつれ、見にくくなってきますし、読みやすいコードを書けるようになりたいと思いました。 1通りアプリが完成したら、次はクラスなどをもっと利用して、同じアプリを作ってみようと思います。
jimbe

2019/05/27 07:55

nextToken は取り出すメソッドなので, 書き込むような操作は出来ません. ですので, 一度変数に取り出して(`String a=stringTokenizer.nextToken();`) その変数の中身をチェック・必要なら変更(`if(a.equals("")) a=null;`)をしてからリストに格納(`tempList.add(a);`)すれば良いかと思います。
sekaikan_ozaki

2019/05/27 08:35

取り出す専用のメソッドだったわけですね、理解しました! 参考にちょっと書き変えてみました。 while (count <= 5) {//countが6以上で読み取り終了 line = bufferReader.readLine();//1行ずつデータを読み込み StringTokenizer stringTokenizer = new StringTokenizer(line, ",");//CSVがカンマ区切りなので、文字列をStringTokenizerでカンマ区切り String a = stringTokenizer.nextToken();//timeList用 String b = stringTokenizer.nextToken();//tempList用 String c = stringTokenizer.nextToken();//amountList用 if(a.equals("")) { a = null; count ++; } timeList.add(a); if(b.equals("")) { b = null; count ++; } tempList.add(b); if(c.equals("")) { c = null; count ++; } amountList.add(c); } bufferReader.close(); } catch (Exception e) { e.printStackTrace(); } これでアプリを実行すると、「時間」も「気温」も「電車の本数」も1時~4時までしか表示されません。(なぜ4時までなのかというと、例のCSVファイルの電車が、5時台が歯抜けになっているから、初めての歯抜けセルの登場) また、それ以降の時刻を入力すると、「時刻が間違っています」になります。。 ということで、4時台までは、リストにどしどし追加されていってwhile文が問題なく回っているのですが、5時台でnullをうまく設定できていないのでしょうか。。 考えられるとすれば、たぶんif文より先に、StringTokenizer stringTokenizer = new StringTokenizer(line, ",");で、空のトークンを取得しようとしているからうまくいってないような気もするのですが...
jimbe

2019/05/27 09:34

StringTokenizer は名前の通り「トークンに分解するため機能を提供するクラス」ですので, new した時点では line が文字列であるということ以上は(中身は)気にしていないでしょう. メインは nextToken メソッドで「現在位置より ',' を探してそこまでの文字列を返す. 現在位置は ',' の次を指すように変更しておく」という方と思います. 動作が想定と違う場合, まず変数の値がどうなっているかご確認ください. この場合 a,b,c がきちんと取れているか, count の値は何処で変化しているか( if 文に入って count を加算していないか), 等ですね.
jimbe

2019/05/27 10:11 編集

調べましたら nextToken はトークンが無くなると例外になるのでした. 5時の行の c を取る nextToken が例外を発して(`catch(EXception e)`を通って)読み込みが中断されています. また, "," が続く場合はまとめて飛ばしてしまうため, "6時,,6本" では "6本" が c では無く b に入ってしまいます. これはやはり StringTokenizer では難しいということでしょう. String.split を使うように書き換えては如何でしょうか.
sekaikan_ozaki

2019/05/27 13:25

StringTokenizerはトークンが必ず存在すること前提だったのですね。。それだと、歯抜けは難しそうですね... でも、おっしゃられたString.splitを利用すれば、歯抜けもなんとかなりそうで安心してきました! サイトを参考にプログラムを書き換えて見ているのですが、配列として受け取ってることが前提のようで、a,b,cがただのStringの変数として受け取ろうとするとエラーになり、それぞれのリストに変数を入れていくことができません。。 String line = ""; int count = 0; while (count <= 5) {//countが6以上で読み取り終了 line = bufferReader.readLine();//1行ずつデータを読み込み 配列として受け取る必要がある?↓ String a = line.split(",");//timeList用 String b = line.split(",");//tempList用 String c = line.split(",");//amountList用 if(a.equals("")) { a = null; count ++; } timeList.add(a); if(b.equals("")) { b = null; count ++; } tempList.add(b); if(c.equals("")) { c = "null"; count ++; } amountList.add(c); } stringTokenizerの時みたく、一時変数に入れてif文で比べたいだけなのですが、どう書き換えれば望み通りの結果が得られるのでしょうか...
jimbe

2019/05/27 14:15 編集

String.split は内部で全体を分解して, それぞれの入った配列を返します. 先の a,b,c で書きますと StringTokenaizer stringTokenizer = new StringTokenizer(line, ","); String a = stringTokenizer.nextToken(); String b = stringTokenizer.nextToken(); String c = stringTokenizer.nextToken(); が String tokens[] = line.split(","); String a = tokens[0]; String b = tokens[1]; String c = tokens[2]; となる感じです. ですが配列に入れてくれるのでわざわざ a,b,c, に入れる必要は無く, そのまま if(a.equals("")) { a = null; count ++; } を if(tokens[0].equals("")) { tokens[0] = null; count++; } とすれば個々の変数は必要ありません. ただしご注意なのは, split でも最後の "," の後が空の場合は配列の件数が減ります. と言いますか, もし "," の数自体が少ない行があると, それにあわせて配列の長さが変わりますので, b や c の位置となる tokens[1] 以降の配列を参照する場合は, 配列の長さのチェックを参照より前( ‘if(tokens.length > 1 && tokens[1].equals("")){`)に行う必要がありますし, 配列が足りないならば null の上書きもできません. ですので, 別途 list に設定する用の配列(例: String data[13])を用意し, null で初期化してから line.split() の結果配列を for で(空文字チェックをしつつ)入れる等が良いかと思います. String tokens[] = line.split(","); String data[13]; for(int i=0; i<data.length; i++) data[i]=null; for(int i=0; i<data.length && i<tokens.length; i++) { if(tokens[i].equals("")) tokens[i] = null; data[i] = tokens[i]; } //data[0]~data[12] にデータが入っている.
sekaikan_ozaki

2019/05/27 15:04 編集

ご丁寧な回答本当にありがとうございます。 splitにも気をつけるべきポイントがあるという点も大変勉強になります。 とりあえず、「時間」と「気温」と「電車」の配列3個の体で、コードを書き直させていただいております。 String line = ""; int count = 0; while (count <= 5) {//countが6以上で読み取り終了 line = bufferReader.readLine();//1行ずつデータを読み込み String tokens[] = line.split(","); String data[] = new String[3];//String data[3];だとエラーが出たので書き換えました for(int i = 0; i < data.length; i++){ data[i] = null; } for(int i=0; i < data.length && i < tokens.length; i++) { if(tokens[i].equals("")){ tokens[i] = null; } data[i] = tokens[i]; }//data[0]~data[2] にデータが入っている. //↓このそれぞれのLIstの記述もしないと、それぞれのリストにデータが入らず、アプリの画面にリストが表示されないはず? if(tokens[0].equals("")) { tokens[0] = null; count++; } timeList.add(tokens[0]); if(tokens.length > 1 && tokens[1].equals("")) { if (tokens[1].equals("")) { tokens[1] = null; count++; } } tempList.add(tokens[1]); if(tokens.length > 1 && tokens[1].equals("")) { if (tokens[2].equals("")) { tokens[2] = null; count++; } } amountList.add(tokens[2]); } このように書き換えました。 が、リストが、「気温」の「5度」まで表示されてますが、「電車」の「5本」以降は全く何も表示されずに、挙動もうまく行かなかったです... >別途 list に設定する用の配列(例: String data[3])を用意し, line.split() の結果配列を for で(空文字チェックをしつつ)入れる 3個それぞれのListに入れるためのデータは、どちらの配列になるのでしょうか...??
jimbe

2019/05/27 16:26

> String data[3];だとエラーが出た あ, ごめんなさい, その通りでした. どうも java と c を同時にやっているとごちゃごちゃに orz data への代入のループにより, 空文字の null 化と, 最後の "," の後にデータが無い場合の配列数の減少に既に対処していますので, その後の編集は不要です. ちょっと, 説明でコードが断片になってしまったので, 全体が見え難くなってしまいました. whlie の中を纏めると↓になります. line = bufferReader.readLine();//1行ずつデータを読み込み if(line == null) break; //行が無くなったら終了(←こういった, メソッドの戻り値の変化にはなるべく対処するようにしてください. どのような場合にどんな戻り値になるかはドキュメントに書かれています.) String tokens[] = line.split(",");// "," で分解 String data[] = new String[3];//この宣言はwhileループの外でも良いです. for(int i = 0; i < data.length; i++){ //data配列の初期化 data[i] = null; } for(int i=0; i < data.length && i < tokens.length; i++) {//「分解したデータ」か「必要なデータ」の少ないほうの分だけループ if(tokens[i].equals("")){ //空文字を null 化 tokens[i] = null; } data[i] = tokens[i]; } //ここまでで data[0]~data[2] にデータが揃っている. timeList.add(data[0]); tempList.add(data[1]); amountList.add(data[2]);
sekaikan_ozaki

2019/05/27 17:05 編集

夜分までお手伝いいただきありがとうございます。 jimbeさまのお書きになられたコードで実行を試みましたが、アプリが立ち上がったと思った瞬間ダウンしてしまいました... 数回実行し直しても、「アプリが何度も停止しています」と表示され、デモすらできない状況です。。。 一つ気になった点は、 int count = 0; while (count <= 5) {//countが6以上で読み取り終了 で、count<=5 の間はループするつもりなのですが、NULLを発見した際にカウントアップしていないことです。 これは、前半で if(line == null) break; としていることからwhile(1)とした方がよかったのでしょうか。
sekaikan_ozaki

2019/05/27 17:08

while(1)はなぜかboolean型じゃないとダメだったようで、代わりにwhile(true)で実行試みましたが、アプリがダウンします...
jimbe

2019/05/27 17:09

> アプリが立ち上がったと思った瞬間ダウン 重々ご免なさい, やはりせめて実行してみるべきですね. 後程やってみます. > while (count <= 5) に関しましては, テスト用と見て count++ を放置しました. そのままでも while(true) と同じです.
sekaikan_ozaki

2019/05/27 17:16

私のためにここまでしてくださり、感謝しかありません。 お時間ある時でよろしいので、その際に可能な範囲でお手伝いいただければ大変うれしいです。 countアップしなければ、実質無限ループということですね、理解しました。
jimbe

2019/05/27 17:43

念のため, 現在の readCSV をご提示しておいて頂けますか. 読んだ CSV の中身は上の「歯抜けが5箇所ある」24行のデータで宜しいですか. > 実質無限ループ そういうことですね.
sekaikan_ozaki

2019/05/27 17:58

かしこまりました。 では一応今回加工しているコード類を全部載せます ↓activity.java ```java package com.example.csvread4; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.Spinner; import android.widget.TextView; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; public class MainActivity extends AppCompatActivity { //リストの宣言 private ArrayList<String> timeList; private ArrayList<String> tempList; private ArrayList<String> amountList; //アダプターの宣言 private ArrayAdapter arrayAdapter; private ArrayAdapter arrayAdapter2; private ArrayAdapter arrayAdapter3; private TextView textView;//適合した際に文章を表示 private EditText editText;//時刻を入力 String text;//入力内容 String item;//気温or電車の本数 private String spinnerItems[] = {"選択", "気温", "電車の本数"};//スピナー //private TextView SpinnertextView;//現在のスピナーで選んでるやつの表示用 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //フレームワーク作成 timeList = new ArrayList<String>(); tempList = new ArrayList<String>(); amountList = new ArrayList<String>(); //CSVを読み込んでおく readCSV(); //時刻の情報 arrayAdapter = new ArrayAdapter( this, R.layout.list_item_layout , timeList); //気温の情報 arrayAdapter2 = new ArrayAdapter( this, R.layout.list_item_layout , tempList); //電車の本数 arrayAdapter3 = new ArrayAdapter( this, R.layout.list_item_layout , amountList); //アプリにCSVの中身を表示するためのインスタンスを作成 ListView listView = (ListView) findViewById(R.id.list_view1); ListView listView2 = (ListView) findViewById(R.id.list_view2); ListView listView3 = (ListView) findViewById(R.id.list_view3); //画面内に表示 listView.setAdapter(arrayAdapter); listView2.setAdapter(arrayAdapter2); listView3.setAdapter(arrayAdapter3); //文字を入力 editText = findViewById(R.id.edit_text); //入力した文字を表示する為の準備 textView = findViewById(R.id.text_view); //ボタンの作成 Button button = findViewById(R.id.button); //検索条件(気温or電車の本数)を選択 //SpinnertextView = findViewById(R.id.spinner_text_view); Spinner spinner = findViewById(R.id.spinner); // ArrayAdapter ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, spinnerItems); //ユーザーが選択しようとするときにドロップダウンによりリストを表示するのに使うレイアウトを指定 adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); // spinner に adapter をセット spinner.setAdapter(adapter); // リスナーを登録 spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { // アイテムが選択された時 @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { Spinner spinner = (Spinner)parent; item = (String)spinner.getSelectedItem();//選択されたアイテムが表示されてスピナーが閉じられる //SpinnertextView.setText(item); } // アイテムが選択されなかった public void onNothingSelected(AdapterView<?> parent) { // } }); //検索ボタンが押されたら button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // エディットテキストの文字を取得 text = editText.getText().toString(); //入力された時刻と適合する時刻を探すメソッド match(text); } }); } /** * CSVの読み込み */ /* public void readCSV() { try { //assetsからCSVファイルの読み込み InputStream inputStream = getResources().getAssets().open("data11.csv"); //1行ずつ読み込みを行うための変換 InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferReader = new BufferedReader(inputStreamReader); String line = ""; while ((line = bufferReader.readLine()) != null) {//1行ずつデータを読み込み StringTokenizer stringTokenizer = new StringTokenizer(line, ",");//CSVがカンマ区切りなので、文字列をStringTokenizerでカンマ区切り timeList.add(stringTokenizer.nextToken()); tempList.add(stringTokenizer.nextToken()); amountList.add(stringTokenizer.nextToken()); } bufferReader.close(); } catch (Exception e) { e.printStackTrace(); } } */ /** * CSVの読み込み */ public void readCSV() { try { //assetsからCSVファイルの読み込み InputStream inputStream = getResources().getAssets().open("hanuke1.csv"); //1行ずつ読み込みを行うための変換 InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferReader = new BufferedReader(inputStreamReader); String line = ""; int count = 0; while (count <= 5){//countが6以上で読み取り終了 line = bufferReader.readLine();//1行ずつデータを読み込み if(line == null) break; //行が無くなったら終了(←こういった, メソッドの戻り値の変化にはなるべく対処するようにしてください. どのような場合にどんな戻り値になるかはドキュメントに書かれています.) String tokens[] = line.split(",");// "," で分解 String data[] = new String[3];//この宣言はwhileループの外でも良いです. for(int i = 0; i < data.length; i++){ //data配列の初期化 data[i] = null; } for(int i=0; i < data.length && i < tokens.length; i++) {//「分解したデータ」か「必要なデータ」の少ないほうの分だけループ if(tokens[i].equals("")){ //空文字を null 化 tokens[i] = null; } data[i] = tokens[i]; } //ここまでで data[0]~data[2] にデータが揃っている. timeList.add(data[0]); tempList.add(data[1]); amountList.add(data[2]); } bufferReader.close(); } catch (Exception e) { e.printStackTrace(); } } //入力された文字(時刻)と適合する時刻を探すメソッド public void match(String text){ String time; String temp = ""; String amount = ""; int find = -1; //時刻の情報を1番目から最後まで回す for(int i=0; i < timeList.size(); i++) { time = timeList.get(i); if (time.equals(text)) {//入力情報と一致したら temp = tempList.get(i); amount = amountList.get(i); find = 1; break; } } if(find == 1) { if(temp == null){ textView.setText("情報が入っていませんでした"); }else if(amount == null){ textView.setText("情報が入っていませんでした"); } if(item == spinnerItems[1]) {//スピナーで選択した条件が「気温」だったら textView.setText(text + "の" + spinnerItems[1] + "は"+temp+"です"); }else if(item == spinnerItems[2]) {//条件が「電車の本数」だったら textView.setText(text + "の" + spinnerItems[2] + "は"+amount+"です"); } }else if(find == -1){ textView.setText("時刻が間違っています"); } } } ``` ↓hanuke1.csv ```csv 時間,気温,電車の本数 1時,1度,1本 2時,2度,2本 3時,3度,3本 4時,4度,4本 5時,5度, 6時,,6本 7時,7度,7本 8時,8度,8本 9時,9度,9本 10時,10度,10本 11時,11度,11本 12時,12度,12本 13時,,13本 14時,14度,14本 15時,15度,15本 16時,16度,16本 17時,17度,17本 18時,18度,18本 19時,19度, 20時,20度,20本 21時,21度,21本 22時,,22本 23時,23度,23本 24時,24度,24本 ```
sekaikan_ozaki

2019/05/27 17:58

↓activity_main.xml ```xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:id="@+id/spinner_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:textColor="#00f" android:textSize="20sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.2" /> <Spinner android:id="@+id/spinner" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_gravity="right" android:background="#fff" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.3" /> <TextView android:id="@+id/text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:layout_gravity="center" android:textSize="30sp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintHorizontal_bias="0.6" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.15" /> <EditText android:id="@+id/edit_text" android:layout_width="wrap_content" android:layout_height="wrap_content" android:autofillHints="@string/hint" android:background="#ffffff" android:layout_gravity="center" android:hint="@string/hint" android:inputType="text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.3" /> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:text="@string/button" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_bias="0.45" /> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <ListView android:id="@+id/list_view1" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"></ListView> <ListView android:id="@+id/list_view2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"></ListView> <ListView android:id="@+id/list_view3" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"></ListView> </LinearLayout> </LinearLayout> ``` ↓list_item_layout.xml ```xml <?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="50dp" android:layout_marginLeft="10dp" android:gravity="center" android:orientation="vertical" android:text="TEXT" android:textAppearance="?android:attr/textAppearanceMedium" android:textColor="@android:color/black"></TextView> ``` ↓strings.xml ```xml <resources> <string name="app_name">CSVread4</string> <string name="button">検索</string> <string name="hint">時刻を入力してください</string> </resources> ``` 以上となります
sekaikan_ozaki

2019/05/27 18:02

>読んだ CSV の中身は上の「歯抜けが5箇所ある」24行のデータで宜しいですか. 歯抜けが5箇所は合ってます。 カテゴリが1行目に入るので、載せたデータの通り、25行になります。
jimbe

2019/05/27 18:41

ありがとうございました. 実行して異常停止しましたので logcat の検索欄に csvread4 と入れると, NullPointerException が見えました. readCSV で tempList 等に null が入りましたが, ArrayAdapter 経由で ListView が null を取り込み, 文字列化のため toString メソッドを呼ぼうとして例外になっています. ArrayAdapter を止めてアダプタを自作するか, 「データが無い」ことの表現を null ではなく ""(空文字) ということにして readCSV メソッドを修正し, match メソッドの `temp == null` 等の箇所を `temp.equals("")` に変えるか, ということになると思います.
sekaikan_ozaki

2019/05/28 02:48 編集

ありがとうございます! 結論から言いますと、nullの箇所をすべて""(空文字)で置き換えたところ、アプリがを正常に動作させることができました! ずっと丁寧におしえていただき本当にありがとうございます。 matchメソッドの自分で書いたコードが少し単純に間違えていた("情報が入っていませんでした"の出力ミス)ので、 if(find == 1) { if(temp == null){ textView.setText("情報が入っていませんでした"); }else if(amount == null){ textView.setText("情報が入っていませんでした"); } if(item == spinnerItems[1]) {//スピナーで選択した条件が「気温」だったら textView.setText(text + "の" + spinnerItems[1] + "は"+temp+"です"); }else if(item == spinnerItems[2]) {//条件が「電車の本数」だったら textView.setText(text + "の" + spinnerItems[2] + "は"+amount+"です"); } }else if(find == -1){ textView.setText("時刻が間違っています"); } を if(find == 1) { if(item == spinnerItems[1]) {//スピナーで選択した条件が「気温」だったら if(temp.equals("")){ textView.setText("情報が入っていませんでした"); } else { textView.setText(text + "の" + spinnerItems[1] + "は"+temp+"です"); } }else if(item == spinnerItems[2]) {//条件が「電車の本数」だったら if(amount.equals("")){ textView.setText("情報が入っていませんでした"); }else { textView.setText(text + "の" + spinnerItems[2] + "は"+amount+"です"); } } }else if(find == -1){ textView.setText("時刻が間違っています"); } } これにしたことで、アプリの文字出力も完ぺきになりました。 ちなみに、今回の件で、そもそもエラーが起きる原因を当初は勘違いしていたりしたことから、デバッグなどの知識もつけていく必要があると感じました。 logcatなどIDEの中で、まだ使ってないツールがあるので、そういうところも使いこなせるように勉強して、今後のより発展的な開発につなげていこうと思いました。 本当にありがとうございました。
sekaikan_ozaki

2019/05/28 02:51

ベストアンサーにしたいところですが、こちらだとできないようなので、次回以降答えてくださる際は是非回答の方にお願い致します!笑
jimbe

2019/05/28 07:28

それで, 結局のところ, 13列18万行 40MB の CSV の読み込みは成功されたのでしょうか. BA を付けないと閉じられないと思いますので, 結果としての原因と修正などを纏めて自己回答にBAされては如何でしょう. 出来ましたら, 「大きなテキストファイルを読もうとしているけど出来ない!」と悩んで teratail を見た方が, こちらの BA 回答を見て「あ、そうか!」となるように…大変ですけれど.
sekaikan_ozaki

2019/05/28 13:58

例のCSVの読み込みも問題なくできました。 しかし、まだまだ次にやりたいことも出てくると思うので、また機会があれば色々ご教授願えればと思います。 >BA を付けないと閉じられないと思いますので, 結果としての原因と修正などを纏めて自己回答にBAされては如何でしょう. わかりました、そうしてみます!
guest

回答2

0

自己解決

当初は、質問タイトルのように、CSVのファイルサイズの大きさが原因だと自分で思い込んで、質問したが、回答者さまとのやりとりを続けるに連れて、原因が別にあるのでは?と思い、その原因を直したところ、。問題なくCSVを読み込むことができ、アプリを正常に動作させることに成功した。

アプリが落ちる根本の原因は、読み取りたいCSVファイルの中身が、ところどころ歯抜けのセルがあったことである。
StringTokenizerを用いて、行のそれぞれのセルをトークンとして扱うつもりだったが、StringTokenizerで用いるnextTokenはトークンが無くなると例外処理をすることがわかった。
そこで、歯抜けのセルを、読み取るようにするために、String.splitを用いて、NULLではなく、""として、変数に格納することで、歯抜けセルに空文字を入れて、文字が入ってないように見せかけることに成功した。
結果、例外になる原因を排除できたことにより、アプリが正常に動作することが確認された。

投稿2019/05/28 14:10

sekaikan_ozaki

総合スコア65

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

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

0

CSVを一括して読み込んでコケるのであれば、CSVデータを1行づつ読んで(あるいは数十行づつ読んで)データ展開、を繰り返していけばどうでしょう。

投稿2019/05/24 05:45

y_waiwai

総合スコア87749

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

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

sekaikan_ozaki

2019/05/24 06:52 編集

回答ありがとうございます。 そういった方法があるんですね。 1つのCSVファイルを途中まで読み込んでデータ展開を繰り返すというのは、途中で読み込みをストップしたりする必要がありますが、現在書いているコードのどこを具体的に書き換えればよろしいのでしょうか? /** * CSVの読み込み */ public void readCSV() { try { InputStream inputStream = getResources().getAssets().open("data.csv"); InputStreamReader inputStreamReader = new InputStreamReader(inputStream); BufferedReader bufferReader = new BufferedReader(inputStreamReader); String line = ""; while ((line = bufferReader.readLine()) != null) { StringTokenizer stringTokenizer = new StringTokenizer(line, ","); No.1List.add(stringTokenizer.nextToken());//1列目の読み取り NO.2List.add(stringTokenizer.nextToken());//2列目の読み取り NO.3List.add(stringTokenizer.nextToken()); NO.4List.add(stringTokenizer.nextToken()); NO.5List.add(stringTokenizer.nextToken()); NO.6List.add(stringTokenizer.nextToken()); NO.7List.add(stringTokenizer.nextToken()); NO.8List.add(stringTokenizer.nextToken()); NO.9List.add(stringTokenizer.nextToken()); NO.10List.add(stringTokenizer.nextToken()); NO.11List.add(stringTokenizer.nextToken()); NO.12List.add(stringTokenizer.nextToken()); NO.13List.add(stringTokenizer.nextToken()); } bufferReader.close(); } catch (IOException e) { e.printStackTrace(); } }
y_waiwai

2019/05/24 07:05

このコードだとファイルを1行づつ読み込んでるので問題なさそうですね しかし40M程度でおちるのかなあ。。 ここのcatchで、すべての例外を対象にするとなにか引っかからないでしょうか
sekaikan_ozaki

2019/05/24 08:39

色々考えて頭がこんがらがっており、1つ質問させていただきたいのですが、y_waiwai様がここで言う「1行」というのは13列(セルでいうと列A~N)をまとめた1行という意味ではなくて、まずNo.1List.add(stringTokenizer.nextToken());でA1のセルを読み取って、NO.2List.add(stringTokenizer.nextToken());でB1のセルを読み取って、NO.13List.add(stringTokenizer.nextToken());でN1のセルを読み取ってから、 再びNo.1List.add(stringTokenizer.nextToken());に戻ってA2のセルを読む、という流れで正しいでしょうか...?(自分でもコードを理解しきれていない部分があっての確認です、すみません。。。) 40MBというサイズは、普通のファイルではあまりいかない数値だと思い、これが原因だと思った理由ですね。。。 本当はSQLiteなどで、データベースに用意しているデータにアクセスできるようにした方が、アプリとしては重たくならず好都合なのでしょうか? catchのprintStackTrace();ですが、これまで呼んだメソッドを保存(スタック)しておいて、どこで例外が起きたのかを突き止めるための便利なメソッドであると調べました。 しかし、EventLogでは何も表示されず、アプリが立ちあがったと思ったら、すぐにダウンしてしまいます。 ちなみに、「すべての例外を対象にする」というのは、この部分のコードに何か追記などするべきなのでしょうか?? 色々質問攻めしてしまい申し訳ありません。。。
y_waiwai

2019/05/24 08:58

> 「1行」というのは13列(セルでいうと列A~N)をまとめた1行という意味 です。 おかしくなってる場所というのは特定されてるんでしょうか。そのCSV読み込みのところで明らかにおかしいというのであれば、 catch のところを、 } catch (Exception e) { にかえてやってみてください
sekaikan_ozaki

2019/05/27 01:15

返信が遅くなってしまい申し訳ありません。 catch (IOException e) { e.printStackTrace(); } から catch (Exception e) { } に変えたところ、アプリが正常に起動しました。 しかし、18万行あるうちの、1~14000行目くらいまでは読み込めていたのですが、それ以降は読み込めませんでした。 やはり、CSVのデータ量の問題で違いないとは思います。。 次の操作をするまでの間にCSVの読み込みが終わりきっていないということでしょうか。。
y_waiwai

2019/05/27 03:40

いやいや、読み込まない、で終わってはダメでしょう catch (Exception e) { e.printStackTrace(); } にしといて、e.printStackTrace();の行にブレークポイント設定して、なんの例外が出たのかを把握しましょう。 その例外によって対処が変わります
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問