使用skip(Long.MAX_VALUE)计算InputStream长度时遭遇FileInputStream.seek(Long.MAX_VALUE)无效参数问题
使用skip(Long.MAX_VALUE)计算InputStream长度时遭遇FileInputStream.seek(Long.MAX_VALUE)无效参数问题
嘿,我之前也踩过这个坑!你想用skip(Long.MAX_VALUE)来计算InputStream的长度,这个思路在处理普通流的时候还行,但碰到FileInputStream就栽在seek(Long.MAX_VALUE)的无效参数问题上了对吧?
问题根源
其实FileInputStream的skip方法底层是依赖seek实现的,当你传入Long.MAX_VALUE这种超大值时,它会尝试执行seek(当前指针位置 + Long.MAX_VALUE),这个值远远超过了绝大多数文件的实际大小,甚至可能超出系统允许的文件偏移量范围,直接触发了无效参数的异常。
解决办法
给你几个实用的处理方案,按需选就行:
1. 针对FileInputStream用NIO通道直接获取大小(最靠谱)
FileInputStream可以通过NIO的通道直接获取文件的真实大小,完全绕开skip和seek的坑:
public int size(String teslaContentEntry) { int result = 0; try (InputStream stream = read(teslaContentEntry)) { if (stream != null) { try { if (stream instanceof FileInputStream) { // 用NIO通道直接拿文件大小 long fileSize = ((FileInputStream) stream).getChannel().size(); result = (int) Math.min(Integer.MAX_VALUE, fileSize); } else { // 非文件流继续用skip的方式兼容 result = (int) Math.min(Integer.MAX_VALUE, stream.skip(Long.MAX_VALUE)); } } finally { StreamUtil.close(stream); } } } catch (IOException e) { // 这里可以根据业务加异常处理,比如打日志或者返回默认值 e.printStackTrace(); } return result; }
2. 通用方案:循环读取计数(兼容所有InputStream)
如果你的代码需要处理各种类型的InputStream(比如网络流、内存流),循环读取直到末尾累加长度是最通用的方式,不会有任何特殊实现的坑:
public int size(String teslaContentEntry) { int result = 0; byte[] buffer = new byte[4096]; // 用4KB缓冲区,平衡性能和内存 try (InputStream stream = read(teslaContentEntry)) { if (stream != null) { int readBytes; while ((readBytes = stream.read(buffer)) != -1) { result += readBytes; // 防止超过Integer.MAX_VALUE,提前截断 if (result >= Integer.MAX_VALUE) { result = Integer.MAX_VALUE; break; } } } } catch (IOException e) { e.printStackTrace(); } return result; }
3. 兼容优化:限制skip的最大范围
如果一定要用skip,可以先预估一个合理的最大skip值,比如用一个比Long.MAX_VALUE小很多的安全值(比如1024L * 1024L * 1024L,也就是1GB),避免触发seek的参数异常,但这个方式不如前两种可靠。
注意点
- 如果你处理的文件可能超过
Integer.MAX_VALUE(也就是2GB),建议把返回类型改成long,用int会导致数据溢出,得到错误的长度。 - 一定要确保流的关闭逻辑正确,try-with-resources是最好的方式,避免资源泄漏。
内容来源于stack exchange
相关产品推荐
相关产品推荐

