readLine() возвращает null, даже если в файле есть содержимое

#java #csv #file-io #null #readline

#java #csv #file-io #null #readline

Вопрос:

Предполагается, что метод numberOfFields() определяет, сколько столбцов существует в определенной строке csv-файла. Я ожидаю 7, но мой вывод получается равным 0; именно так я инициализировал cols. Итак, я использовал system.out.println() внутри цикла while и выяснил, что цикл while не вводится. В моем файле много строк текста, поэтому я не понимаю, почему readLine() возвращает null. Не уверен, где еще я могу ошибаться.

 public class CSVReader {

    public BufferedReader bR1;

    public CSVReader(Strin& 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;

        Strin& line;
        while ((line=bR1.readLine()) != null) {
            Strin&Tokenizer st = new Strin&Tokenizer(line, ",");
            while (st.hasMoreElements()) {
                st.nextToken();
                cols  ;
            }
        }
        return cols;

   
  

Комментарии:

1. Насколько я могу судить, это зависит от того, как вы вызываете свой numberOfFields метод. Для чего это значение row ? Потому что, если вы пропустите весь CSV-файл в первом цикле while, во втором цикле while не останется строк для чтения читателем. Вам следует изучить это поведение и, возможно, объяснить, чего вы пытаетесь достичь с помощью первого цикла.

2. Если вы вызываете numberOfFields() более одного раза, все вызовы, кроме первого, завершатся неудачей, поскольку bR1 больше не располагается в начале файла. На самом деле он расположен в конце файла, поскольку именно там первый вызов покинул программу чтения.

3. @Andreas На самом деле я вызываю этот и другой метод (numberOfRows()) более одного раза, и я полагаю, что вы разобрались с проблемой. Прямо сейчас указатель находится в конце файла после вызова функции numberOfRows() для определения количества строк в файле. Есть ли способ переместить указатель на начало файла?

4. @maloomeister вызов был: numberOfFields(10); где я хочу узнать количество полей в 10-й строке. Цель первого цикла while (rows<строка) — поместить мой указатель на строку прямо перед строкой, в которой мне нужно найти количество полей, чтобы затем я мог использовать Strin&Tokenizer. Кроме того, файл содержит 214 строк, поэтому не должно быть никаких проблем с отсутствием строк для чтения.

Ответ №1:

На мой взгляд, могут быть две причины :

  1. заданный вами параметр row превышает номер строки файла.
  2. ваше имя файла неверно.

Я предлагаю вам добавить System.out.println(bR1.readLine) в первый цикл while, чтобы посмотреть, что произошло.

Комментарии:

1. На мой взгляд, причина в том, что numberOfFields() вызывается более одного раза.

2. Итак, я сделал то, что вы предложили, и получил null в качестве выходных данных. Но я думаю, что это из-за того, что упомянул Андреас. После вызова метода для определения количества строк мой указатель теперь находится в конце файла и, следовательно, равен null. Есть ли способ переместить указатель на начало файла?

3. BufferedReader.mark(int) и BufferedReader.reset() могут выполнять this.@eva

Ответ №2:

InputStream Может быть прочитан только один раз.

Если вы вызываете numberOfFields() более одного раза, все вызовы, кроме первого, завершатся неудачей, поскольку bR1 больше не располагается в начале файла. На самом деле он расположен в конце файла, поскольку именно там первый вызов покинул программу чтения.

Вместо открытия потока в конструкторе, пусть каждый метод откроет свой собственный поток.

В дальнейшем эти проблемы были исправлены:

  • Использование try-with-resources для правильной обработки закрытия потока.

    Функция Try-with-resources была добавлена в Java 7, поэтому, если вы не работаете на старых версиях Java, нет абсолютно никаких веских причин использовать ее.

  • Изменен код, чтобы считать только столбцы строки запроса, а не столбцы всех оставшихся строк.

  • Использование Strin&Tokenizer было заменено регулярным выражением. Как говорит javadoc из Strin&Tokenizer :

    Strin&Tokenizer это устаревший класс, который сохраняется по соображениям совместимости, хотя его использование не рекомендуется в новом коде. Рекомендуется, чтобы все, кто ищет эту функциональность, использовали вместо split метода Strin& или java.util.re&ex пакета.

 public class CSVReader {

    public final Strin& fileName;

    public CSVReader(Strin& 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
            Strin& line = bR1.readLine();
            return (line == null ? 0 : line.split(",", -1).len&th);
        }
    }