hadoop之IOUtils是否需要关闭流?

本文探讨了在Hadoop中使用IOUtils.copyBytes方法后,输入输出流是否需要手动关闭的问题。作者通过实验发现,当从Main方法调用时,流会在程序结束时自动关闭,而在Web端调用时,由于FileSystem类的特性,流可能不会被及时关闭,导致问题出现。解决方案包括使用带close参数的方法或手动调用FileSystem.CloseAll。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很久没写blog,有很多值得写的地方。慢慢补。

Hadoop中有个常用的方法org.apache.hadoop.io.IOUtils.copyBytes(InputStream in, OutputStream out, int buffSize),用于将本地文件上传至hdfs。

入参数in和out用完后是否需要关闭呢?显而易见的是流用完后需要关闭,但是经验告诉我,每次写mapreduce,我从未关闭过,也未曾出过问题。

本以为是方法中替我关闭了它,直到我遇见了一个意外。


我在一段程序中调用copyBytes(),之后流依旧未关闭。我测试的时候使用Main()去调用程序,每次程序都能正常结束。

而我将程序入口改为一个Web端的点击。用于启动这个方法的时候,程序却永远无法输出到目标位置上。很是奇怪。

Web端的点击和Main()的区别在哪里?

Main()方法结束后,程序会自动释放,难道释放后程序才关闭了流?显然Web程序是个永不结束的长程序,不满足这个条件。

我最先想到的finalize(),我们知道这个方法不靠谱。但是我去检索hadoop源码,发现有些地方会重写这个方法,多少还都和流有点关系。

但是我在IOUtils中并没有找到finalize()方法,其它类的finalize()调用了流的关闭?依旧没有检索到,很头疼。


就在我快要穷尽所能之时,一个念头闪了过来,钩子!(应该是无意中看到了某处源码)

在org.apache.hadoop.fs.FileSystem中2442行有如下代码:

ShutdownHookManager.get().addShutdownHook(clientFinalizer, SHUTDOWN_HOOK_PRIORITY);

我们去看clientFinalizer这个类:

    private class ClientFinalizer implements Runnable {
      @Override
      public synchronized void run() {
        try {
          closeAll(true);
        } catch (IOException e) {
          LOG.info("FileSystem.Cache.closeAll() threw an exception:\n" + e);
        }
      }
    }

由于hdfs的out都是由FileSystem根据对应Path创建而来,跟踪源码,发现Close就是delete(Path)

我们有足够的理由相信,就是这些代码造成了我们的困惑。

Web端点击,FileSystem是一个长驻内存的类,所以除非容器Shutdown,否则该类不会被释放,也就是说HOOK也永远不会被执行。

而Main方法或者MapReduce的结束,则HOOK被调用起来,流也就被关闭。

对程序进行debug的时候,我手动FileSystem.CloseAll()会立即提交到HDFS,而不用等到程序运行结束。这也验证了我的猜想。


当然我们还有其它方法解决这个问题:

例如copyBytes(InputStream in, OutputStream out, int buffSize, boolean close) ,最后一个参数就是一个不错的扩展。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值