我只是打了Java文件系统API,并来到了以下的功能,用来拷贝二进制文件。原来源来自于网上,但是我加了尝试/赶/最后条款可以肯定的是,如果东西是错误的发生,缓冲区流将被关闭(和因此,我的操作系统资源释放)之前退出的功能。

我修剪下来的功能,显示的模式:

public static void copyFile(FileOutputStream oDStream, FileInputStream oSStream) throw etc...
{
   BufferedInputStream oSBuffer = new BufferedInputStream(oSStream, 4096);
   BufferedOutputStream oDBuffer = new BufferedOutputStream(oDStream, 4096);

   try
   { 
      try
      { 
         int c;

         while((c = oSBuffer.read()) != -1)  // could throw a IOException
         {
            oDBuffer.write(c);  // could throw a IOException
         }
      }
      finally
      {
         oDBuffer.close(); // could throw a IOException
      }
   }
   finally
   {
      oSBuffer.close(); // could throw a IOException
   }
}

据我了解,我不能把两个 close() 在最后条款,因为第一个 close() 可能扔掉,然后,第二次不会被执行。

我知道C#有 处置 模式,将处理这个的 using 关键词。

我甚至不知道更好C++码就已经喜欢的东西(使用Java-API):

void copyFile(FileOutputStream & oDStream, FileInputStream & oSStream)
{
   BufferedInputStream oSBuffer(oSStream, 4096);
   BufferedOutputStream oDBuffer(oDStream, 4096);

   int c;

   while((c = oSBuffer.read()) != -1)  // could throw a IOException
   {
      oDBuffer.write(c);  // could throw a IOException
   }

   // I don't care about resources, as RAII handle them for me
}

我失去了一些东西,或者我真的已经产生的丑陋和臃肿的代码在Java只是为了处理例外情况 close() 方法的一个缓冲流?

(请告诉我,我是错的地方...)

编辑:是我,或者在更新这一页面上,我看到两个问题和所有的答案下降一个点,在一个几分钟吗?是有人享受自己太多而建设和平委员会组织委匿名?

编辑2: 麦克道尔 提供了一个非常有趣的链接我觉得我必须在这里提到的:http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html

编辑3:以下麦克的链接,我跌提议Java7的一个模式类似的C#使用的模式: http://tech.puredanger.com/java7/#resourceblock .我的问题是明确地描述。显然,即使有Java7 do, 问题依然存在。

有帮助吗?

解决方案

试用/最终模式是正确的方式来处理流在大多数情况下Java6和降低。

有些倡导默默地关闭流。小心这样做对于这些原因: Java:怎么不做一个混乱的流处理


Java7引入了 尝试与资源:

/** transcodes text file from one encoding to another */
public static void transcode(File source, Charset srcEncoding,
                             File target, Charset tgtEncoding)
                                                             throws IOException {
    try (InputStream in = new FileInputStream(source);
         Reader reader = new InputStreamReader(in, srcEncoding);
         OutputStream out = new FileOutputStream(target);
         Writer writer = new OutputStreamWriter(out, tgtEncoding)) {
        char[] buffer = new char[1024];
        int r;
        while ((r = reader.read(buffer)) != -1) {
            writer.write(buffer, 0, r);
        }
    }
}

AutoCloseable 类型将自动关闭:

public class Foo {
  public static void main(String[] args) {
    class CloseTest implements AutoCloseable {
      public void close() {
        System.out.println("Close");
      }
    }
    try (CloseTest closeable = new CloseTest()) {}
  }
}

其他提示

有问题,但你发现躺在约在网络上的代码是真正的穷人。

关闭缓冲流下方关闭该流。你真的不希望这样做。所有你想要做的就是刷新输出流。也有在指定的基本流是文件没有意义的。性能很烂,因为你是在同一时间(实际上,如果你使用的java.io使用可以使用的transferTo / transferFrom这是一个快一点还是)复制一个字节。虽然我们看好它,变量名吮吸到。所以:

public static void copy(
    InputStream in, OutputStream out
) throw IOException {
    byte[] buff = new byte[8192];
    for (;;) {
        int len = in.read(buff);
        if (len == -1) {
            break;
        }
        out.write(buff, 0, len);
    }
}

如果你发现自己使用try-最后很多,那么你就可以用“执行围绕”成语因素吧。

在我看来:Java的应该有好歹在范围结束时关闭资源。我建议增加private作为一元后缀运算收于封闭块的末尾。

是的,这就是java的是如何工作的。有控制反转 - 对象的用户必须知道如何清理的对象,而不是自己后清理对象本身。这不幸导致大量的清理代码散布在整个Java代码。

C#具有“使用”的关键字来自动调用Dispose当对象超出范围。 Java有没有这样的事情。

不幸的是,这种类型的代码往往会在Java中有点臃肿。

顺便说一句,如果调用oSBuffer.read或oDBuffer.write之一抛出一个异常,那么你可能需要让该异常渗透到调用层次。

具有无人看守的呼叫以关闭()的一个最后子句内将导致原始异常由一个由闭合产生被替换() - 调用。换句话说,一个失败的close() - 方法可以隐藏()由读产生的原来的异常或写()。所以,我觉得你要忽略close()方法,如果的且仅当的其他方法没有抛出。

抛出的异常

我通常包括显式近距离呼叫时,内部的try内部解决这个问题:

  try {
    while (...) {
      read...
      write...
    }
    oSBuffer.close(); // exception NOT ignored here
    oDBuffer.close(); // exception NOT ignored here
  } finally {
    silentClose(oSBuffer); // exception ignored here
    silentClose(oDBuffer); // exception ignored here
  }
  static void silentClose(Closeable c)  {
    try {
      c.close();
    } catch (IOException ie) {
      // Ignored; caller must have this intention
    }
  }

最后,对于性能,代码应该可能与缓冲器(每个读/写多个字节)工作。不能备份,通过数字,但更少的调用应该是更有效的比顶部添加缓冲数据流。

有关通用IO任务,如拷贝一个文件,代码诸如上文所示重新发明轮子。不幸的是,JDK不提供任何更高级别的实用工具,但是Apache公地-io的一样。

例如,文件实用程序包含的文件和目录(包括复制)工作的各种实用方法。在另一方面,如果你真的需要使用JDK的IO支持的 IOUtils 包含一套closeQuietly的(),该关闭读者方法,作家,流等未抛出异常。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top