【问题标题】:Strange behavior of Nested while loop while iterating over a text file迭代文本文件时嵌套while循环的奇怪行为
【发布时间】:2018-03-10 11:44:12
【问题描述】:

我是 Java 新手。我正在尝试遍历几个 .txt 文件以将文件的一行与第二个文件的每一行进行比较。这是我的两个文件:listread.txtcsvread.txt

这是我正在使用的代码:

try {
        BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"));
        BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
        String csvItem, listItem;
        int count =0;
        while((csvItem = csvReader.readLine()) != null){
            System.out.println("before second loop:"+csvItem);
            while ((listItem = listReader.readLine())!= null) {
                System.out.println("list Item: "+listItem.toLowerCase().split("¬")[1]);
                System.out.println("csv Item: "+csvItem.toLowerCase());
                if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
                        count++;
                }
             }
        }

    }catch(Exception e){
            e.printStackTrace();
    }

当我运行它时,只有csvread.txt 中的第一行(存储在变量csvItem 中)与listread.txt 中的所有行进行比较。这是一个示例输出:

before second loop:Record Category   
list item: provisions
csv Item: record category    
list item: request category
csv Item: record category    
list item: elevator
csv Item: record category    
list item: assessment
csv Item: record category    
list item: associates
csv Item: record category    
list item: score
csv Item: record category    
list item: attachments
csv Item: record category

它只遍历list.txt 文件的所有行以及csvread.txt 文件的第一行。没有移动到csvread.txt 的第二行,程序结束在最后抛出一个错误:

java.lang.ArrayIndexOutOfBoundsException: 1
    at test.main(test.java:52)

指的是System.out.println("list item: "+listItem.toLowerCase().split("¬")[1]);这一行。这个声明与我猜的迭代无关。不知道为什么会抛出这个错误..

但是,当我注释掉第二个 for 循环时,它可以很好地迭代 csvread.txt 文件中的所有行。这是一个示例输出,只有第一个 while 循环和第二个循环被注释掉:

before second loop:Record Category   
before second loop:Type 
before second loop:Name
before second loop:State
before second loop:Number
before second loop:ID (Self)
before second loop:Parent
before second loop:Title

仅当存在嵌套循环时才会出现此问题。当有一个循环时,完全没有问题。有人可以对这种奇怪的行为有所了解吗?还有怎么克服呢?

编辑: 我添加了一个if 条件来检查该行是否包含¬,因为我在该字符上拆分该行:

 if(listItem.contains("¬")){
        System.out.println("list item: "+listItem.toLowerCase().split("¬")[1]);
        System.out.println("csv Item: "+csvItem.toLowerCase());
        if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
                count++;
         }
   }

不,我不再遇到异常。但是,行为仍然很奇怪。这是添加if后的输出:

before second loop:Record Category   
    list item: provisions
    csv Item: record category    
    list item: request category
    csv Item: record category    
    list item: elevator
    csv Item: record category    
    list item: assessment
    csv Item: record category    
    list item: associates
    csv Item: record category    
    list item: score
    csv Item: record category    
    list item: attachments
    csv Item: record category
    before second loop:Type 
    before second loop:Name
    before second loop:State
    before second loop:Number
    before second loop:ID (Self)
    before second loop:Parent
    before second loop:Title

其他元素现在在csvread.txt 中被迭代,但与listread.txt 中的行的比较除了第一个元素外没有增加。

任何帮助将不胜感激。谢谢!

【问题讨论】:

  • 您有一行没有 ¬ ,因此它不会被拆分,并且数组没有索引为 1 的元素。从解决这个问题开始。
  • 此外,在第一次迭代中,内部循环读取到 list.txt 文件的末尾,因此 listReader 指向文件的末尾。在下一次外循环迭代中,由于listReader 已经指向文件的末尾,因此内循环不会被执行。
  • 那么,它是这样工作的吗?我如何让它重新开始?有没有更好的迭代方式? @AndrewS

标签: java loops while-loop


【解决方案1】:

当您使用嵌套循环时,内部循环会完全执行。然后执行控制从内​​循环出来,开始外循环的下一次迭代。因此,如果要逐行比较两个文件的内容,则不应有任何内部循环。下面是在这种情况下您可以尝试执行的示例代码。不过,我还没有测试过。

try {
    BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"));
    BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
    String csvItem, listItem;
    int count =0;
    while((csvItem = csvReader.readLine()) != null){
        System.out.println("before second loop:"+csvItem);
        listItem = listReader.readLine();
        if (listItem != null){
            if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
                    count++;
            }
        }else{
            //The listItem has no more lines to compare, so ending the process.
            break;
        }
    }

}catch(Exception e){
        e.printStackTrace();
}

我希望这会有所帮助。

注意:上面的答案是基于一个信念,即要求是逐行比较两个文件的内容。

【讨论】:

  • 感谢您的回答。但是,这种方法不允许我将第一个文件的单行与第二个文件的所有行进行比较。它只是一对一比较。
  • 哦,我明白了。我认为一对一的比较是这里的意图。
【解决方案2】:

您的访问权限

listItem.toLowerCase().split("¬")[1]

很关键,因为您总是希望所有行都有您的“¬”。如果不是这种情况,您的拆分将不会返回数组,并且您访问位置 [1] 的返回数组,该数组失败并返回 IndexOutOfBounds....

【讨论】:

    【解决方案3】:

    从我关于listReader 在第一次迭代后指向文件末尾的评论扩展而来。 BufferedReader 没有提供移动文件指针的机制,因此一种简单的方法是将 listReader 的创建移动到外循环内部:

    try {
        BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"));
        // BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
        String csvItem, listItem;
        int count =0;
        while((csvItem = csvReader.readLine()) != null){
            System.out.println("before second loop:"+csvItem);
            BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
            while ((listItem = listReader.readLine())!= null) {
                System.out.println("list Item: "+listItem.toLowerCase().split("¬")[1]);
                System.out.println("csv Item: "+csvItem.toLowerCase());
                if(listItem.toLowerCase().split("¬")[1].contains(csvItem.toLowerCase())){
                        count++;
                }
             }
        }
    
    }catch(Exception e){
            e.printStackTrace();
    }
    

    所以每次迭代都会有一个新的listReader,它从文件顶部开始。

    但这可能是太多的 I/O。如果 list.txt 的大小不是太大,那么也许读取一次,解析它,然后存储在 Set<String> 中以供以后比较:

        try (BufferedReader listReader = new BufferedReader(new FileReader("/data/list.txt"));
                BufferedReader csvReader = new BufferedReader(new FileReader("/data/csvread.txt"))) {
            String listItem = null;
            Set<String> listItems = new HashSet<>();
            while ((listItem = listReader.readLine()) != null) {
                listItems.add(listItem.toLowerCase().split("¬")[1]);
            }
    
            String csvItem;
            int count = 0;
            while ((csvItem = csvReader.readLine()) != null) {
                System.out.println("before second loop:" + csvItem);
    
                for (String item : listItems) {
                    System.out.println("list Item: " + item);
                    System.out.println("csv Item: " + csvItem.toLowerCase());
                    if (item.contains(csvItem.toLowerCase())) {
                        count++;
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    还移至 try-with-resources 以确保 csvReaderlistReader 正确关闭。

    【讨论】:

    • 我还没有尝试过第一种方法。但我确信第二种方法有效。感谢您的精彩回答! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多