Чтение одного InputStream из нескольких методов - PullRequest
0 голосов
/ 04 августа 2011

Я инициализировал InputStream в одном методе в классе и передал его следующему методу для обработки. InputStream по существу инкапсулирует CSV-файл для обработки.

Другой метод вызывает 2 разных метода, передавая один и тот же InputStream один для получения заголовков, а другой для обработки содержимого. Структура выглядит примерно так, как указано ниже:

main() {
  FileInputStream fis = new FileInputStream("FileName.CSV");
  BufferedInputStream bis = new BufferedInputStream(fis);
  InputStreamReader isr = new InputStreamReader(bis);

  processCSV(isr);
}

processCSV(Reader isr) {
  fetchHeaders(isr);
  processContentRows(isr);
}

fetchHeaders(Reader isr) {
  //Use BufferedReader to retrieve first line of CSV
  //Even tried mark() and reset() here
}

processContentRows(Reader isr) {
  //Cannot read the values, fetches null from InputStream :(
}

Я что-то здесь не так делаю? Есть ли способ, которым я могу повторно использовать InputStream в различных вызовах методов.

Я устанавливаю полную программу, которая может имитировать проблему ниже:

  import java.io.FileInputStream;
  import java.io.BufferedInputStream;
  import java.io.InputStreamReader;
  import java.io.BufferedReader;

  public class MarkResetTest
  {
    public static void main(String a[])
    {
        FileInputStream fis = null;
        BufferedInputStream bis = null;
        InputStreamReader isr = null;
        BufferedReader br = null;
        BufferedReader br2 = null;

        try {
            fis = new FileInputStream("C:/Test/Customers.csv");
            bis = new BufferedInputStream(fis);
            isr = new InputStreamReader(bis, "Unicode");    

            System.out.println("BR readLine()");        

            br = new BufferedReader(isr);
            //System.out.println(br.markSupported());
            br.mark(1000);
            System.out.println(br.readLine());
            br.reset();
            //System.out.println(br.readLine());            

            System.out.println("BR2 readLine()");

            br2 = new BufferedReader(isr);
            System.out.println(br2.readLine());
        }
        catch(Exception e) {
            System.out.println("Exception::" + e);
        }
        finally {
            try {
                br.close();
                isr.close();
                bis.close();
                fis.close();
            }
            catch(Exception e) {
                System.out.println("Exception while closing streams :: " + e);
            }
        }
    }
  }

Ответы [ 3 ]

4 голосов
/ 04 августа 2011

Проблема заключается в создании двух BufferedReader поверх одного и того же Reader.Когда вы читаете данные из BufferedReader, скорее всего, они прочитают больше, чем данные, которые они возвращают, в свой буфер (отсюда и имя).Другими словами, даже если вы прочитали только одну строку из BufferedReader, InputStreamReader может иметь намного больше данных, прочитанных с него - так что если вы прочитаете снова из этого InputStreamReader тогда вы пропустите эти данные.Данные фактически были высосаны из InputStreamReader в BufferedReader, поэтому единственный способ передать их клиентскому коду - это прочитать их из этого BufferedReader.

Другими словами, вы утверждаете, что:

Нет.fetchHeaders () читает только первую строку CSV, содержащую заголовки.

неверно.Он только использует такого количества данных, но он читает больше из InputStreamReader.

Как сказал Илья, вы должны создать только один BufferedReader поверхисходный InputStreamReader и передать его в оба метода.

fetchHeaders может затем использовать это BufferedReader для чтения строки, а processContentRows может делать то, что ему нравится, с BufferedReader при этомточка - это всего лишь Reader, насколько это необходимо знать.

Итак, чтобы немного изменить пример Ильи:

public static void main(String[] args) {
  FileInputStream fis = new FileInputStream("FileName.CSV");
  BufferedInputStream bis = new BufferedInputStream(fis);
  InputStreamReader isr = new InputStreamReader(bis);
  BufferedReader br = new BufferedReader(isr);

  processCSV(br);
}

private static void processCSV(BufferedReader reader) {
  fetchHeaders(reader);
  processContentRows(reader);
}

private static void fetchHeaders(BufferedReader reader) {
   // Use reader.readLine() here directly... do *not* create
   // another BufferedReader on top.
}

private static void processContentRows(Reader reader) {
  // This could be declared to take a BufferedReader if you like,
  // but it doesn't matter much.
}
1 голос
/ 04 августа 2011

Если вам нужен BufferedReader, я думаю, вам нужно создать его в основном методе:

main() {
  FileInputStream fis = new FileInputStream("FileName.CSV");
  BufferedInputStream bis = new BufferedInputStream(fis);
  InputStreamReader isr = new InputStreamReader(bis);
  BufferedReader br = new BufferedReader(isr);

  processCSV(br);
}

processCSV(Reader isr) {
  fetchHeaders(isr);
  processContentRows(isr);
}

fetchHeaders(Reader isr) {
  //Use BufferedReader to retrieve first line of CSV
  //Even tried mark() and reset() here
}

processContentRows(Reader isr) {
  //Cannot read the values, fetches null from InputStream :(
}
1 голос
/ 04 августа 2011

Вы не делаете ничего плохого. Просто убедитесь, что метод, открывающий поток / читатель, также закрывает его в блоке finally.

...