我需要关闭FileInputStream吗?

35

我正在测试自动化领域担任实习生。 我使用Eclipse创建Junit代码并在Eclipse中运行。 在此过程中,我使用FileInputStream函数从Excel表格中检索数据。

FileInputStream fi=new FileInputStream("c:\\search.xls");
Workbook w=Workbook.getWorkbook(fi);
Sheet s=w.getSheet(0);

关闭Inputstream函数是必要的吗?如果是,请给我一些示例代码。

10个回答

36

是的,如果您想释放系统资源,您需要 close 输入流。

FileInputStream.close() 就是您所需的方法。


在JUnit测试中需要吗?进程结束后资源不会被释放吗? - Dmitry Avgustis
在进程退出后,就没有什么可以利用的了。所以,操作系统会回收资源。但是,想法是保持测试以稳定的方式运行,而不是等待退出来完成工作。就像问“如果我关闭设备怎么办?” :-) 另外,这取决于操作系统。请查看此问题doesnt-the-jvm-release-all-the-resources-that-are-not-explicitly-closed-by-the-programmer以获取更多详细信息。 - asgs

10

您需要使用 close() 方法关闭文件,或结束程序运行。

如果不关闭文件,可能会遇到以下问题:

  • 有时测试是单独运行的,或者一组测试在同一个进程中运行(这可能导致测试在某些情况下正常运行,在其他情况下则出现问题)
  • 无法重命名或删除处于打开状态的文件。

最佳实践是在完成资源后始终关闭它们,但是我认为单元测试是一些脚本,不一定要严格遵循最佳实践。


1
关闭资源的好理由。我会把“打开文件过多”和内存泄漏加入到这个列表中,尤其是对于长时间运行的进程。 - Elist
@Elist 需要在垃圾回收之间有很长时间,因为它们会在清理时关闭。 - Peter Lawrey
1
真实情况下,进程的长寿可能通常不是原因。更常见的情况是递归读取文件/目录会导致“打开文件过多”。无论触发器是什么,我自己都见过这两种情况,所以这是一个真实的场景。 - Elist

9
FileInputStream fi=null;
try {
    fi=new FileInputStream("c:\\search.xls");
    Workbook w=Workbook.getWorkbook(fi);
    Sheet s=w.getSheet(0);
} finally {
    if (fi!=null) {
        fi.close();
    }
}

7
只是一个小建议 - 你还需要用 try/catch 包装 close() 语句,因为 close() 声明会抛出一个已检查的 IOException。实际上,你不能像那样只使用 finally。你只能在运行时异常中使用 try/finally。但对于像 IOException 及其子类这样的已检查异常,你必须有一个 try/catch 或者 try/catch/finally...不仅有 try/finally 是不会编译通过的。 - luis.espinal
3
这句话的意思是:这取决于方法是否声明了 IOException,如果你捕获了它,你应该知道如何处理它。重要的部分是将 close() 放在 finally 块中。事实上,自动处理这一点是我真正期待在 Java 7 中看到的功能之一。 - Axel

6
是的!在使用完资源后,您应该始终释放它们。Java有一个强大的垃圾收集机制(请注意,与资源管理/泄漏不同)。因此,垃圾收集器无法确定您将来是否需要该资源?未能释放资源可能会导致拒绝服务、性能差等问题。
如前所述,但另一种更轻松的方法是使用“尝试资源关闭”(try with resources)(try with resources)
    try (FileInputStream fi = new FileInputStream("c:\\search.xls")) {

         //do something with fi.
         //fi.getChannel() ;

    } catch(IOException e) {
        // exception handling.
    } finally {
    // some statements for finally.
   }

现在您不需要显式地调用fi.close()方法。

6

关闭你使用的资源总是一个好主意,但是:

如果你在资源B中使用资源A,并且它有一个关闭方法,那么关闭B而不是A是明智的。

在您的情况下,您在Workbook中使用FileInputStream,因此最好关闭Workbook并依赖于Workbook来关闭FileInputStream

实际上,在这种特殊情况下,Workbook将在getWorkbook()方法结束时关闭FileInputStream,但是关闭Workbook以使其能够被垃圾收集仍然是一个好主意。关闭


这其实是一个更好的答案。我在两个对象上都调用了close/release。 - Hitesh Kumar Saini
@HiteshKumarSaini Closeable A类的构造函数接受Closeable B类类型的构造函数参数并不意味着A将如何处理B的close()方法。Workbook类不会关闭InputStream。请参见下面的答案。 - cquezel

1

Workbook 实现了 Closeable 接口,这意味着您应该调用 close() 方法或使用 try-with-resources 来释放 Workbook 对象获取的资源。

仅仅观察 Workbook 有一个 close() 方法,并不能得出 InputStream 资源的使用方式。

实际上,Workbook 构造函数使用流来初始化自身。构造函数不保留对流的引用。Workbook 构造函数不关闭 InputStream。关闭 InputStream 是您的责任,您可以在构造 Workbook 对象后立即执行此操作。因此,以下代码是正确的:

private static Workbook getWorkbook() throws IOException {
    try (InputStream is = ...) {
        return WorkbookFactory.create(is); // newer API
    }
}

    try (Workbook workbook = getWorkbook()) {
        Sheet sheet = workbook.getSheet("SheetName");
        ...
    }

0

我使用这种方式来确保关闭Excel文件输入流,这可能会有所帮助。

abstract int workWithWorkBook(Workbook workBook);

protected int doWorkBook(Path excelFile) throws IOException {
    File f = excelFile.toFile();

    try (FileInputStream excelContent = new FileInputStream(excelFile.toFile())){
        POIFSFileSystem fileSystem = new POIFSFileSystem(excelContent);
        Workbook workBook = null;
        if (f.getName().endsWith("xls")) {
            workBook = new HSSFWorkbook(fileSystem);
        } else if (f.getName().endsWith("xlsx")) {
            workBook = new XSSFWorkbook(excelContent);
        }
        return workWithWorkBook(workBook);

    }catch (Exception e){
        e.printStackTrace();
        throw e;
    }
}

9b9ea92b-5b63-47f9-a865-fd40dd602cd5


0
最近,我尝试重构我的代码时,必须将工作簿创建移到另一个方法中,并且FileInputStream是在该方法中创建的。该方法创建一个FileInputStream并返回一个Workbook对象。但是,在主方法中看不到FileInputStream,那么我如何在主方法的结尾关闭FileInputStream呢?答案是,你不必关闭FileInputStream,相反,只需关闭Workbook对象,它会在内部关闭FileInputStream。简而言之,说你无论如何都必须关闭FileInputStream是不正确的。

但是 Workbook 接口没有名为 close 的方法,我该如何关闭 Workbook - Yu Jiaao
你确定Workbook的close()方法会关闭InputStream吗?请看下面我的回答。 - cquezel

0

做类似这样的事情。

FileInputStream fi=null;
try{
fi = new FileInputStream("c:\\search.xls");
Workbook w=Workbook.getWorkbook(fi);
Sheet s=w.getSheet(0);
}catch(IOException ioe){
}finally{
if(fi != null){
fi.close();
}
fi = null;//This will be hint to get finalize() called on fi so that underlying resources used will released like files opened.
}

-1

计算机科学101告诉我们确保在Java或任何语言中关闭打开的资源。因此,是的,您需要关闭它们。如果不这样做,就会发生糟糕的事情。

此外,您应该学习(并有倾向)使用Javadocs。查看FileInputStream和Closeable的Javadoc,答案就在那里。


3
盲目地遵循既定规则而不批判性思考并了解"为什么?"部分是一种非常糟糕的方法。坏事情会发生——哦,普通?编程不是巫术,不提及未正确释放资源的后果(例如文件无法移动,通常可能会引入内存泄漏,操作系统文件句柄池可能会耗尽),你的答案是无用且有害的。被踩。 - om-nom-nom
1
哦,我使用一种语言表达方式,而你却说“天哪,他相信巫术”(与“呵呵,他没有详细说明,而是选择了一些俚语”相反)。还有很多其他的回应没有详细说明后果,除非你去贬低他们,否则你只是在一个有偏见的高马脚上攀登一堆肥皂盒子。为什么我不详细说明问题(以及为什么这个帖子中的大多数人也没有)?因为它们很容易找到适当的文献,对于任何进行一点点研究的人都可以获得。如果你认为这不合适,那就是你的选择。 - luis.espinal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接