从多个方法读取单个InputStream

mav*_*ckm 0 java inputstream java-io

我已经在类中的单个方法中初始化了一个InputStream,并将其传递给下一个方法进行处理。InputStream本质上封装了用于处理的CSV文件。

另一种方法调用传入同一 InputStream 的 2 个不同方法,一个用于检索标头,另一个用于处理内容。该结构如下所示:

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 :(
}
Run Code Online (Sandbox Code Playgroud)

我在这里做错了什么吗?有什么方法可以在不同的方法调用之间重用 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);
            }
        }
    }
  }
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 5

问题在于BufferedReader在同一个 s 之上创建两个 s Reader。当您从 读取数据时BufferedReader,它可能会读取比返回的数据更多的数据到其缓冲区中(因此得名)。换句话说,即使您只从 中读取了一行BufferedReader,也InputStreamReader可能从中读取了更多数据 - 因此,如果您再次从中InputStreamReader读取,那么您将错过该数据。数据已被有效地从 吸到因此将其发送到客户端代码的唯一方法就是从 读取数据。InputStreamReader BufferedReaderBufferedReader

换句话说,您的主张是:

没有。fetchHeaders() 仅读取包含标题的 CSV 的第一行。

是不正确的。它只使用那么多数据,但它InputStreamReader.

BufferedReader正如 Ilya 所说,您应该只在原始的基础上创建一个InputStreamReader,并将其传递给这两种方法。

fetchHeaders然后可以使用它BufferedReader来读取一行,并且可以在此时processContentRows执行它喜欢的操作- 这只是它需要知道的范围。BufferedReaderReader

所以稍微修改一下 Ilya 的例子:

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.
}
Run Code Online (Sandbox Code Playgroud)