使用写入和读取流Java

时间:2016-03-14 16:05:01

标签: java inputstream outputstream

我总是看到这样:

int count = line.read(buffer, 0, buffer.length);
if (count > 0) {
  out.write(buffer, 0, count);
}

其他例子

byte[] buffer = new byte[1024]; // Adjust if you want
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
  output.write(buffer, 0, bytesRead);
}

...其他

  int numRead;
  while ( (numRead = is.read(buf) ) >= 0) {
      os.write(buf, 0, numRead);
  }

我从未见过这样的事情:

  while (true) {
    try {
      output.write(BytesArray, 0, input.read(BytesArray, 0, BytesArray.length)); //Single line for read and write!!!!
    } catch (IOException e) {
        System.out.println("I can't write!");
        break;
    } catch (ArrayIndexOutOfBoundsException e) {
        System.out.println("I can't read!");
        break;
    }
  }

使用OuputStream有什么问题写入最近由InputStream读取的somethig?

有问题吗?

修改 InputStream.readOutputStream.write工作时正常工作,而在另一工作失败时失败;以同样的方式OutputStream.writeInputStream.read这样做时起作用,当另一个也没有这样做时停止。

InputStream.read(...)失败(或无法阅读更多)时,此方法返回-1;但是,当OutputStream.write(...)失败(或无法写更多)时,此方法会抛出IOException异常。

我个人认为:当OutputStream.write(...)无法写入时,应该返回“-1”,与InputStream.read(...)无法读取的方式完全相同。

问题: 相信你InputStream.read(...)OutputStream.write(...)应该以相同的方式处理它们(都返回-1)?

注意:我知道OutputStream的这种方法:public void write(...)

1 个答案:

答案 0 :(得分:2)

使用异常处理来执行控制流 - 当由于API而不必要时 - 是不好的做法。

如果您希望这样做的原因是您可以在一行上写下语句,那么您应该评估为什么您认为在一行上编写语句更好的原因。我的手机上有一个足够大的屏幕,可以同时显示上面的所有四个例子 - 而且我的手机上没有代码 - 所以我无法想象在一条线路上写东西的情况#34;因为我可以在一条线上写它"是一个引人注目的原因。

另外,考虑一下您是否能够在一行中编写某些语句的事实确实使代码整体更短:

while (true) {
  try {
    output.write(buffer, 0, input.read(buffer, 0, buffer.length);
  } catch (ArrayIndexOutOfBoundsException e) {
    break;
  }
}

(我在这里忽略了IOException,正如你在前3个例子中所做的那样 - 你需要在编写代码时进行处理,因此它与数量方面的4个版本之间的差异无关代码)。

将此与方法2中的等效代码(最接近的等价物)进行比较:

int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
  output.write(buffer, 0, bytesRead);
}

更简洁。

但是,正如我在上面提到的那样,代码的简洁并不是衡量代码质量的标准,因此,就其本身而言,这并不是解雇提议版本的理由。然而,有更多根本原因导致它不是一个好的方法......

在建议的代码中,有两种预期类型的​​例外:IOExceptionArrayIndexOutOfBoundsException。这些是根本不同的例外:

  • IOException预计会因读取或写入失败而产生(这是一个实际的异常情况,因此适当使用了异常)。

    IOException已检查例外。必须处理已检查的异常(不是编译时错误)。它们旨在表明API无法控制的可恢复条件和条件。例如,如果您正在写入磁盘或网络,则无法控制磁盘是否被其他进程填满,或者承包商是否正在挖掘光纤连接。已检查的异常表示"如果您稍后再试,这可能会成功#34; (当磁盘不满时,或者承包商固定光纤时)

  • ArrayIndexOutOfBoundsException预计会在到达输入流的末尾时产生(这不是一个例外情况,因为几乎所有流都结束了,因此不适合使用异常,也不是必要的异常使用,因为它可以通过read)的返回值检测到。

    ArrayIndexOutOfBoundsException是一个未经检查的异常,它是由编程错误引起的 - 以不打算使用的方式使用API​​。不需要处理未经检查的异常(如果您不这样做,则不是编译时错误),因为它们旨在指示大多数不可恢复的条件,如编程错误。例如,如果您尝试使用特定输入运行某些代码,并且由于编程错误而抛出未经检查的异常,则稍后将抛出相同的未经检查的异常,因为它运行相同的代码。

因此,虽然您可以捕获并从未经检查的异常中恢复,但不是它们的设计目标(这就是为什么你不 >有到)。编写代码更容易,因此异常不会首先发生。

在这种情况下,这很简单:Javadoc for OutputStream说:

  

如果off为否定,或len为否定,或off+len大于数组b的长度,则会引发IndexOutOfBoundsException

所以,满足这些条件,你不必担心它会发生。

(无论如何,你需要抓住IndexOutOfBoundsException而不是ArrayIndexOutOfBoundsException,因为OutputStream的某些实现可能不会抛弃后者。)

但是有一个更深层次的原因,你不应该依赖于为你的控制流程捕获未经检查的异常:你可能没有检测到你认为是的条件。

任何类型的未经检查的异常都可以从特定调用的调用链中的任何位置抛出 - 您可能期望它正在发生,因为OutputStream.write不喜欢否定len参数,但它可以实际OutputStream.write中的任何其他内容调用 - 或InputStream.read - 或者他们称之为传递的任何其他方法 - 您无法确定(不检查堆栈跟踪;但是,您应该检查堆栈跟踪的详细信息是特定于实现的,因此需要花费很多精力才能使其足够强大)

如果您认为此异常意味着您已到达流的末尾,那么您实际上可能正在掩盖您想要知道的代码中的其他一些问题。

因此,最好的做法是编写代码,使依赖于捕获特定的未经检查的异常。如果记录在特定情况下它会抛出这样的例外,避免这些情况