商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Java标准输入输出流的关闭与重置逻辑

Java标准输入输出流的关闭与重置逻辑

  发布于2026-07-10 阅读(0)

扫一扫,手机访问

先说一个核心判断:Ja va 的三个标准流——System.inSystem.outSystem.err——不是你想关就能关的。它们从 JVM 启动那一刻起,就跟操作系统底层的资源绑定在一起,生命周期与进程同生共死。如果强行调用 close(),后续所有操作都会抛出 IOException,而且这个错误是“不可逆”的。这不是 bug,这是语义约束。

Ja va标准输入输出流的关闭与重置逻辑

为什么这三个流不能关闭?

根本原因在于:这些流是 JVM 启动时绑定的底层文件描述符,比如 stdin 对应 fd 0。一旦你调用 System.in.close(),就等于把这个文件描述符释放了。之后 JVM 不会提供任何机制重新建立这个连接——没有“重新打开”这个选项。

几个关键细节:

  • System.in 不支持 mark/reset:它不是 BufferedInputStreammarkSupported() 返回 false,所以别指望通过 reset() 来重复读取输入。
  • 关闭后就是永别:没有 API 能恢复标准输入,甚至 new FileInputStream(FileDescriptor.in) 也不行——因为 FileDescriptor.in 在关闭后已经失效。
  • System.out/err 也一样:关闭之后,println() 会直接抛异常,所有依赖控制台输出的框架、日志系统都会跟着遭殃。

如何安全地“重置”或重复读取输入?

既然不能直接操作 System.in,那就换个思路——数据缓存 + 逻辑复用。具体做法有三种:

  • 一次性读完,再分段处理:用 Scanner(System.in)BufferedReader(new InputStreamReader(System.in)) 把整行或整块数据读入内存,存入 Stringbyte[],后续反复解析这个内存副本即可。
  • 封装成可重读的 InputStream:如果必须传入 InputStream 接口,可以把原始输入内容转换成 ByteArrayInputStream,它天然支持 mark()/reset(),随意重读。
  • 避免直接依赖 System.in:在方法签名中接收 InputStream 参数,而不是硬编码 System.in。这样既方便测试,也方便复用——比如单元测试时直接传入 new ByteArrayInputStream("test".getBytes())

标准流的正确关闭场景

需要调用 close() 的,从来都不是这三个标准流本身,而是你主动创建的、非标准的流实例。比如:

  • new FileInputStream("data.txt") 打开的文件流;
  • new BufferedInputStream(System.in) 包装后的流——注意,这包装的是副本,关闭它不影响 System.in 原始引用,但一般也不建议这样操作;
  • 通过 System.setIn(...) 替换后的自定义输入流——此时它的生命周期就由你负责了。

对于这些流,务必使用 try-with-resourcesfinally 块确保关闭,防止文件句柄泄漏。

重定向后的注意事项

如果通过 System.setIn(new FileInputStream("input.txt")) 重定向了标准输入,有两个关键点:

  • 新设置的流是你自己创建的,必须由你关闭——通常在程序退出前或重置回原 System.in 之后执行;
  • System.in(键盘流)并没有被关闭,只是暂时不可达,重定向操作本身不改变关闭逻辑——你关的是自己 new 出来的流,不是 JVM 的 stdin。

一句话总结:标准流是 JVM 的“私有财产”,别碰它。你的任务是管理好自己创建的那些流。

本文转载于:https://www.php.cn/faq/2799606.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注