【问题标题】:Reading single InputStream from multiple methods从多个方法中读取单个 InputStream
【发布时间】:2011-10-19 20:29:54
【问题描述】:

我已经在一个类的单个方法中初始化了一个 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);
            }
        }
    }
  }

【问题讨论】:

  • 请展示一些在 fetchHeaders 和 processContentRows 中的代码。例如,fetchHeaders 是否真的一直读取到数据的末尾,而不是在 headers 的末尾停止?
  • 不。 fetchHeaders() 仅读取包含标题的 CSV 的第一行。该语句是 br.readLine() 并且它不在循环中。
  • 那么,你能想出一个简短但完整的程序来演示这个问题吗?
  • 嗨乔恩,我已经用示例程序编辑了我的帖子。现在可以结账了吗?

标签: java inputstream java-io


【解决方案1】:

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

换句话说,您声称:

不。 fetchHeaders() 只读取包含 Headers 的 CSV 的第一行。

不正确。它只使用那么多数据,但它读取更多来自InputStreamReader

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

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.
}

【讨论】:

  • 完美的解释。其实这也是我老板告诉我的。 BufferedReader 在缓冲区中吸入更多数据,因此尝试从其他读取器读取它会导致出现空数据。感谢您的建议,我将尝试将建议的代码调整到我的代码中。
【解决方案2】:

如果你需要一个 BufferedReader,我认为你需要在 main 方法中创建它:

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 :(
}

【讨论】:

  • 问题只是 fetchHeaders() 使用的是 BufferedReader。 processContentRows() 使用其他读取器来处理行。
  • AFAIK,BufferedReader 也是 Reader。您可以将其包装在自定义阅读器中,就像使用 InputStreamReader 一样。这也可能会给您带来一些性能提升(因为缓冲)。
  • @mayur:Ilya 的回答是正确的,但我添加了自己的更多细节和更完整的 (IMO) 代码示例。
【解决方案3】:

你没有做错任何事。只需确保打开流/阅读器的方法也会在 finally 块中关闭它。

【讨论】:

  • 流在 main() 中打开和关闭。其他方法只是使用适当的读取方法来读取内容。
猜你喜欢
  • 1970-01-01
  • 2014-06-26
  • 2014-03-31
  • 2023-03-09
  • 2012-03-03
  • 1970-01-01
  • 2019-01-05
  • 1970-01-01
相关资源
最近更新 更多