【问题标题】:readLine() returns null even though file has content即使文件有内容,readLine() 也会返回 null
【发布时间】:2020-11-29 17:32:44
【问题描述】:

numberOfFields() 方法应该找出 csv 文件的特定行中存在多少列。我期待 7 但我的输出结果为 0;这就是我将 cols 初始化为的内容。所以我在while循环中使用了system.out.println(),我发现while循环没有被输入。我的文件有很多文本行,所以我不明白为什么 readLine() 返回 null。不知道我还有什么可能错的地方。

public class CSVReader {

    public BufferedReader bR1;

    public CSVReader(String fileName) throws IOException {
        bR1 = new BufferedReader(new FileReader(fileName));
    }


    public int numberOfFields(int row) throws IOException {
        int rows = 1;
        while (rows < row) {
            bR1.readLine();
            rows++;
        }
        int cols = 0;

        String line;
        while ((line=bR1.readLine()) != null) {
            StringTokenizer st = new StringTokenizer(line, ",");
            while (st.hasMoreElements()) {
                st.nextToken();
                cols++;
            }
        }
        return cols;

   

【问题讨论】:

  • 据我所知,这取决于您如何调用numberOfFields 方法。 row 的值是多少?因为如果您在第一个 while 循环中跳过整个 csv 文件,则在第二个 while 循环中没有任何行可供读者读取。您应该研究这种行为,并解释您通过第一个循环尝试实现的目标。
  • 如果您不止一次调用numberOfFields(),除了第一次调用之外的所有调用都会失败,因为bR1 不再位于文件的开头。它实际上位于文件的末尾,因为第一次调用离开阅读器的位置。
  • @Andreas 事实上,我不止一次地调用了这个方法和另一种方法(numberOfRows()),我相信你已经解决了这个问题。现在,在调用 numberOfRows() 以找出文件中的行数后,指针位于文件的末尾。有没有办法将指针重新定位到文件的开头?
  • @maloomeister 电话是:numberOfFields(10);我希望找出第 10 行中的字段数。第一个 while 循环 (rows

标签: java csv file-io null readline


【解决方案1】:

在我看来,可能有两个原因:

  1. 你给的参数row超过了文件的行号。
  2. 您的文件名错误。

我建议您在第一个 while 循环中添加 System.out.println(bR1.readLine) 以查看发生了什么。

【讨论】:

  • 在我看来,原因是numberOfFields()被多次调用。
  • 所以我按照你的建议做了,我得到了 null 作为输出。但我认为这是因为安德烈亚斯提到的。在调用一个方法来找出行数之后,我的指针现在位于文件的末尾,因此为空。有没有办法将指针重新定位到文件的开头?
  • BufferedReader.mark(int) 和 BufferedReader.reset() 可以做到这一点。@eva
【解决方案2】:

InputStream 只能读取一次。

如果您多次调用numberOfFields(),除了第一次调用之外的所有调用都将失败,因为bR1 不再位于文件的开头。它实际上位于文件的末尾,因为第一次调用离开阅读器的位置。

不要在构造函数中打开流,而是让每个方法打开它们自己的流。

在下文中,这些问题已得到修复:

  • 使用 try-with-resources 正确处理流的关闭。

    Try-with-resources 是在 Java 7 中添加的,因此除非您在 Java 的古老版本上运行,否则绝对没有充分的理由使用它。

  • 将代码更改为仅计算请求行的列,而不是所有剩余行的列。

  • StringTokenizer 的使用已被正则表达式取代。正如StringTokenizer 的 javadoc 所说:

    StringTokenizer 是一个遗留类,出于兼容性原因保留,但在新代码中不鼓励使用。建议任何寻求此功能的人使用Stringsplit 方法java.util.regex 包。

public class CSVReader {

    public final String fileName;

    public CSVReader(String fileName) {
        this.fileName = fileName;
    }

    public int numberOfFields(int row) throws IOException {
        try (BufferedReader bR1 = new BufferedReader(new FileReader(this.fileName))) {
            // Skip row-1 rows
            for (int rows = 1; rows < row; rows++) {
                bR1.readLine();
            }
            
            // Count number of columns in next line, if available
            String line = bR1.readLine();
            return (line == null ? 0 : line.split(",", -1).length);
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-08
    • 2015-12-30
    • 2018-02-12
    • 2021-06-24
    • 1970-01-01
    • 1970-01-01
    • 2017-03-20
    相关资源
    最近更新 更多