InputStream写入File后文件为空,如何排查解决该问题?
解决InputStream写入File后文件为空的问题
这个问题我之前也碰到过!大概率是InputStream的读取位置不对,或者Files.copy的配置有遗漏,给你几个排查和解决的方案:
核心原因分析
你已经确认InputStream本身有内容,那问题基本出在流的读取指针位置或者Files.copy的执行逻辑上:
- 如果在调用
Files.copy之前,任何代码(比如你用来测试的BufferedReader读取逻辑)已经读取过这个InputStream,流的指针会移动到末尾,后续Files.copy就读不到任何内容了。 - 部分InputStream(比如Servlet上传的文件流)不支持
mark()和reset()方法,没法直接把指针移回开头。
解决方案
方案1:缓存流内容到内存(适合小文件)
先把InputStream的内容全部读到内存中,再用缓存后的流去写入文件,这样就不用担心指针位置的问题:
try (InputStream inputStream = file.getInputStream()) { // 缓存流内容到ByteArrayOutputStream ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int readLen; while ((readLen = inputStream.read(buffer)) != -1) { baos.write(buffer, 0, readLen); } // 转成可重复读取的ByteArrayInputStream try (InputStream cachedStream = new ByteArrayInputStream(baos.toByteArray())) { Path filePath = this.rootLocation.resolve(filename); // 确保目标文件的父目录存在 Files.createDirectories(filePath.getParent()); // 覆盖已存在的文件,避免文件已存在导致的异常 long copiedBytes = Files.copy(cachedStream, filePath, StandardCopyOption.REPLACE_EXISTING); // 可以打印字节数确认写入情况 System.out.println("成功写入 " + copiedBytes + " 字节"); } } catch (IOException e) { e.printStackTrace(); }
方案2:直接修复流指针(仅支持可标记的InputStream)
如果你的InputStream支持mark()和reset()(比如FileInputStream),可以在读取前标记位置,读完后重置指针:
try (InputStream inputStream = file.getInputStream()) { // 先测试是否支持标记 if (inputStream.markSupported()) { // 标记流的起始位置,参数为最大缓存字节数 inputStream.mark(Integer.MAX_VALUE); // 这里可以放你用来测试的读取代码 String result = new BufferedReader(new InputStreamReader(inputStream)) .lines().collect(Collectors.joining("\n")); // 重置指针到起始位置 inputStream.reset(); } Path filePath = this.rootLocation.resolve(filename); Files.createDirectories(filePath.getParent()); Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { e.printStackTrace(); }
方案3:简化Files.copy的调用逻辑
你原来的代码里把Path转成File再转回Path完全没必要,直接用filePath即可,同时显式指定复制选项:
try (InputStream inputStream = file.getInputStream()) { Path filePath = this.rootLocation.resolve(filename); Files.createDirectories(filePath.getParent()); // 直接使用Path参数,指定覆盖选项 Files.copy(inputStream, filePath, StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { e.printStackTrace(); }
额外排查点
- 检查
Files.copy的返回值:它会返回实际写入的字节数,如果返回0,说明流确实没有内容(大概率是指针在末尾)。 - 确认目标路径是否正确:可以打印
filePath.toString()看看是不是写到了你预期的目录里。
内容的提问来源于stack exchange,提问作者Айдар Мулюков
相关产品推荐
相关产品推荐

