不能。Files.copy() 支持 InputStream 作为源,但目标必须是 OutputStream(需用 Files.newOutputStream() 转换 Path),不可直接传 Path;否则编译报错,且正确配对才能启用零拷贝优化。

Files.copy() 能不能直接处理 InputStream?
不能。直接传 InputStream 给 Files.copy() 会编译报错——它只接受 Path、InputStream(作为源)或 OutputStream(作为目标),但**必须配对使用**:源是 InputStream 时,目标必须是 OutputStream,而不能是 Path。
正确写法:用 Files.copy(InputStream, OutputStream) + Files.newOutputStream()
核心是把目标文件路径转成 OutputStream,再和输入流一起交给 Files.copy()。这样能复用 NIO 的零拷贝优化(如支持 transferTo 的平台会自动启用),比手动 byte[] 循环快得多。
实操建议:
- 始终用
StandardOpenOption.CREATE_NEW或CREATE明确控制文件创建行为,避免意外覆盖 - 加上
StandardOpenOption.WRITE,否则newOutputStream()默认只读 - 用 try-with-resources 自动关闭流,
Files.copy()不负责关流
示例:
try (InputStream is = getRemoteInputStream();
OutputStream os = Files.newOutputStream(Paths.get("/tmp/data.bin"),
StandardOpenOption.CREATE_NEW, StandardOpenOption.WRITE)) {
Files.copy(is, os);
}
常见错误:忽略异常类型和资源泄漏
Files.copy() 抛的是 IOException,不是 RuntimeException;如果漏关流,尤其在 HTTP 客户端场景下,连接可能被长期占用。
典型坑点:
- 只关了
InputStream,忘了OutputStream—— 两者都得在 try-with-resources 里声明 - 用
Files.copy(is, path)试图偷懒,结果编译失败(参数不匹配) - 没设
CREATE_NEW,目标文件已存在时抛FileAlreadyExistsException,而非静默覆盖
比 FileOutputStream 更推荐的原因
直接 new FileOutputStream 也能工作,但 Files.newOutputStream() 提供更细粒度的控制,比如原子创建(CREATE_NEW)、追加(APPEND)、同步写盘(SYNC)等选项,且语义更清晰。
性能上二者底层都走相同系统调用,差异不大;但 Files.copy() 在某些 JDK 版本 + Linux 环境下能触发 sendfile 优化,跳过用户态内存拷贝——这点手动循环或 FileOutputStream.write() 做不到。
真正容易被忽略的是:如果输入流来自网络(如 HttpURLConnection.getInputStream()),务必确认服务端返回了明确的 Content-Length,否则 Files.copy() 可能因流提前结束而抛 IOException,且错误信息只显示 “stream closed”,不提示源头问题。

















