

初めまして。javaを勉強して3ヶ月程度の者です。  
以下のコードで出力されるテキストファイルがどうしても理想の値になりません。

具体的には、入力に2つのテキストファイルをとります。それぞれのテキストファイルはコンマ区切りのCSVファイルのような形式になっていて、例えば

[code]

    1,2,3,4,5
    2,,5
    
    1,3,5,7,9
    
[/code]

のようになっています。空文字や何も入っていない行もあります。

このコードでやりたいのは、2つのテキストファイルで位置が合致する値を足して新たなテキストファイルに出力することです。先ほどの例とは別に、

[code]

    1,1,1,1,1
    2,2,2,2
    3,3,3
    4,4
    5
    
[/code]

というものを用意したとき、出力は以下のようになります。

[code]

    2,3,4,5,6
    4,2,7,2
    3,3,3
    5,7,5,7,9
    5
    
[/code]

うまくいかない点としては、2行目以降計算が合わない、空行の処理がうまくいかない、出力の方法が正しいか分からない、です。他にもうまくいかない点がきっとあると思いますが、ご教授お願いします。

また、別の方法で良い方法が必ずあると思うので、解決の代替案としてそちらも提案してくださると助かります。

よろしくお願いします。

[code]

    import java.io.*;
    import java.util.*;
    
    public class Num_Array {
        public static void main(String[] args){
            ArrayList<ArrayList<Integer>> list = new ArrayList<ArrayList<Integer>>(); 
            ArrayList<Integer> row;
    
            try{
                FileReader fr = new FileReader("1041.txt");
                FileReader fr2 = new FileReader("1042.txt");
                BufferedReader br = new BufferedReader(fr);
                BufferedReader br2 = new BufferedReader(fr2);
                File f = new File("output104.txt");
                FileWriter filewriter = new FileWriter(f);
                String str1 = null;
                str1 = br.readLine();
                String str2 = null;
                str2 = br2.readLine();
                
                while(str1 != null && str2 != null){
                    int num = 0;
                    int add_num = 0;
     
                    String[] nstr1 = str1.split(",");
                    String[] nstr2 = str2.split(",");
                    row = new ArrayList<Integer>();
               
                    for(int i = 0; i < nstr1.length || i < nstr2.length; i++){
                        if(i < nstr1.length && i < nstr2.length){
                            if(nstr1[i].equals("")){
                                nstr1[i] = "0";
                            }
                            if(nstr2[i].equals("")){
                                nstr2[i] = "0";
                            }
                            //System.out.println(nstr2[i]);
                            num = Integer.valueOf(nstr1[i]);
                            add_num = Integer.valueOf(nstr2[i]);
                            num += add_num;
                            row.add(num);
                        }
                    
                        if(i >= nstr1.length){
                            row.add(Integer.valueOf(nstr2[i]));
                        }else if(i >= nstr2.length){
                            row.add(Integer.valueOf(nstr1[i]));
                        }
                    }
                    list.add(row);
                    str1 = br.readLine();
                    str2 = br.readLine();
                }
                for(int i = 0; i < list.size(); i++){
                    for(int j = 0; j < list.get(i).size(); j++){
                        filewriter.write(String.valueOf(list.get(i).get(j)));
                        if(j != list.get(i).size()-1){
                            filewriter.write(",");
                        }else{
                            filewriter.write("\n");
                        }
                    }
                }
                br.close();
                br2.close();
                filewriter.close();
                fr.close();
                fr2.close();
            }catch(IOException e){
                System.out.println(e.getMessage());
            }
        }
    }
    
[/code]


CC BY-SA 4.0
2020-07-04T14:37:16.013
68275
2020-07-04T21:43:37.303
2020-07-04T16:32:05.057
3060
35091
question
java テキストファイル
javaの文字列とArrayListの扱いが分かりません


問題点が2つあります。

1つめは、次の行を読む際、2つの`BufferedReader`を混同してしまっています。

[code]

    str1 = br.readLine();
    str2 = br.readLine();
    
[/code]

上の引用箇所の2行目は、`br2`が用いられるべきでしょう。

2つめは、ファイルを読み終える条件です。

[code]

    while(str1 != null && str2 != null){
    
[/code]

どちらかが終端に達するとループを抜けるので、行が長い方のファイルが最後まで処理されません。

どちらも`null`になるまで続ける(その際`null`の方にはダミーを設定する)、ような形になるでしょうか。

[code]

    while(str1 != null || str2 != null){
        // ...
        String[] nstr1 = str1 != null ? str1.split(",") : new String[0];
        String[] nstr2 = str2 != null ? str2.split(",") : new String[0];
    
[/code]

* * *

あと、これは直接問題になるわけではないですが、

[code]

    if(i < nstr1.length && i < nstr2.length){
        // ...
    }
    
    if(i >= nstr1.length){
        // ...
    }else if(i >= nstr2.length){
        // ...
    }
    
[/code]

の条件判定は同列なので、

[code]

    if(i < nstr1.length && i < nstr2.length){
        // ...
    } else if(i >= nstr1.length){
        // ...
    } else if(i >= nstr2.length){
        // ...
    }
    
[/code]

とした方が良いかと思います。

* * *

"別の方法で良い方法"については、幅が広いので答えづらいですが、今回の問題について言うと

  * 2つのファイル操作で重複しているものが多いのでメソッド化して見通しを良くする
  * 行の取り扱いが少し特殊なのでクラス化するなどして外からはもう少しシンプルに扱えるようにする

みたいなことが挙げられるかと思います。  
行をクラス化すると、例えば[こんな感じ](https://github.com/yukihane/stackoverflow-
qa/blob/639566bbfc6c18fecd69c72306793abe37bb841a/jaso68275/src/main/java/com/github/yukihane/so/Num_Array2.java#L57-L128)になるかなと思います。


CC BY-SA 4.0
2020-07-04T19:33:08.657
68281
2020-07-04T21:43:37.303
2020-07-04T21:43:37.303
2808
2808
68275
answer