【问题标题】:Why won't the BufferedReader read past the first line of the .csv?为什么 BufferedReader 不能读取 .csv 的第一行?
【发布时间】:2018-03-25 17:03:13
【问题描述】:

我试图跳过 .csv 文件的第一行,这是我的第一个 if 语句应该解决的问题,然后遍历 .csv 文件并创建新的 Call 对象并将它们添加到名为 callList 的数组中。它不会读取第一行,而是读取第一行,然后给我一个NullPointerException。任何想法?为什么会这样?

public static void parseCalls(String fileName) {

    int firstRow = 1;
    int counter = firstRow;
    String line = "";

    try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {

        while ((line = br.readLine()) != null) { 
                if(counter == firstRow) { //should skip first row
                    br.readLine();
                }
                // use comma as separator
                String[] splitCalls = line.split(",");
                callList.add(new Call(splitCalls[6], splitCalls[9], splitCalls[25], splitCalls[17]));
                counter++;
        }

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

}

public static void main(String[] args) {
        parseCalls("test.csv");
}

我的堆栈跟踪是:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 6 at CallAnalyzer.parseCalls(CallAnalyzer.java:95) at CallAnalyzer.main(CallAnalyzer.java:323)

当我调用parseCalls() 时,每个错误发生的位置。

【问题讨论】:

  • 请拨打tour
  • 为什么都是样板文件? Files.lines(...).skip(1).map(line -> line.split(","))

标签: java csv bufferedreader


【解决方案1】:

首先就像蜘蛛鲍里斯在评论中说的那样,您可以使用Files.lines(...).skip(1).map(line -> line.split(",")),但如果您阅读该行但不将其分配给您的行变量,那么您也可以在您的代码中使用。因此,稍后在您的代码中,您尝试拆分包含第一行的变量行的内容。您没有提供堆栈跟踪,但我打赌您的 NullPointerException 发生在 splitCalls[6] 上,而您的 splitCalls 没有第 6 个元素,因为您拆分了错误的行。如果您想保留您的代码,请执行以下操作:

public static void parseCalls(String fileName) {

    int firstRow = 1;
    int counter = firstRow;
    String line = "";

    try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {

        while ((line = br.readLine()) != null) { 
                if(counter == firstRow) { //should skip first row
                    counter++;
                    continue;
                }
                // use comma as separator
                String[] splitCalls = line.split(",");
                callList.add(new Call(splitCalls[6], splitCalls[9], splitCalls[25], splitCalls[17]));
                counter++;
        }

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

}

或者更好:

public static void parseCalls(String fileName) {

    boolean firstRow = true;
    String line = "";

    try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {

        while ((line = br.readLine()) != null) { 
                if(firstRow) { //should skip first row
                    firstRow = false;
                    continue;
                }
                // use comma as separator
                String[] splitCalls = line.split(",");
                callList.add(new Call(splitCalls[6], splitCalls[9], splitCalls[25], splitCalls[17]));
        }

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

}

【讨论】:

  • 谢谢迈克尔!由于某种原因,该函数仍然只读取第一行。我添加了打印语句,并确定当我尝试将新调用添加到 callList 时它会中断 while 循环。 callList 是一个静态的 Array 所以它应该可以在类中进行操作吧?
  • 将堆栈跟踪添加到您的问题描述中,这应该会有所帮助。你得到的仍然是 NullPointerException 吗?
  • 是的,因为我怀疑您的 splitCalls 数组没有第 6 个元素。因此,当您尝试访问它时,它会因此异常而失败。您的 csv 文件无效或由于其他原因拆分出错。通常,在拆分字符串后,您应该检查数组中有多少元素。因为如果您通过尝试访问第 5 个元素仅获得 3 个元素,那么您将因此异常而失败。调试代码并检查数组中有多少元素。一般来说,你真的应该在访问它之前在代码中检查它。
  • 您可以创建一个GetElement 辅助函数来检查请求的索引是否在范围内,如果不在则返回null,如果是则返回元素...
【解决方案2】:
if(counter == firstRow) { //should skip first row
    br.readLine();
}

这里您没有将readLine() 的结果分配给变量line。但是最好把它带出循环,并在进入循环之前读取一行。这样您就不必在每次读取一行时检查第一行。

String[] splitCalls = line.split(",");
callList.add(new Call(splitCalls[6], splitCalls[9], splitCalls[25], splitCalls[17]));

在访问任何元素之前,您应该首先检查splitCalls[] 的长度。永远不应该信任 csv 文件的内容,例如,某些行可能只有 3 列,这会抛出 ArrayIndexOutOfBoundsException (但你现在得到这个的原因是因为 line 仍然包含文件的第一行,并且可能包含较少的项目)。

所以你会有类似的东西:

try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {

    br.readLine();

    while ((line = br.readLine()) != null) { 
            String[] splitCalls = line.split(",");
            // check length of array here, if ok:
            callList.add(new Call(splitCalls[6], splitCalls[9], splitCalls[25], splitCalls[17]));
    }
} catch (IOException e) {
    e.printStackTrace();
}

【讨论】:

    【解决方案3】:

    打电话就行了

    line = br.readLine();
    

    在 if 分支中,然后在拆分之前测试 line != null。否则第一行仍然存储在行中。

    而且它不会只读取我系统上的一行。

    我猜你的第一行是一些评论或标题,没有包含足够的逗号来分割字符串,因此 splitCalls[6] 触发了异常,然后,当然,没有进一步的行被读取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-02
      • 2015-02-07
      • 1970-01-01
      • 2022-11-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多