Java InputStream.read() 为什么返回 int?

Java InputStream.read() 为什么返回 int?

InputStream.read() 返回 int,因为它既要表示 0..255 的字节值,也要用 -1 表示 EOF;若返回 byte,0xFF 也会被误判为结束,导致数据丢失。

一个返回值,要装下两类信息

Java 的 byte 是 8 位有符号类型,范围是 -128 到 127。但文件或网络流里的一个字节有 256 种取值:0x00 到 0xFF。InputStream.read() 将读到的字节按无符号值返回为 0 到 255,并把范围之外的 -1 留作"已经到末尾"的标记。

因此正确的单字节读取方式是先用 int 判断 EOF:

java 复制代码
static void readBytes(Path path) throws IOException {
    try (InputStream in = Files.newInputStream(path)) {
        int value;
        while ((value = in.read()) != -1) {
            // value 一定在 0..255 之间
            consume(value);
        }
    }
}

如果先转成 byte 再判断,问题就出现了:

java 复制代码
int value = in.read();
byte b = (byte) value;

当读到 0xFF 时,value 是 255,但转成 byte 后 b 是 -1。如果在转换前没有检查 value == -1,合法数据和 EOF 就会混在一起。需要保留字节数组时,可以在确认不是 EOF 后再转型。

复制文件时,判断的是"本次读到多少"

复制图片、压缩包等二进制内容,通常用缓冲区,而不是每次只读一个字节:

java 复制代码
static void copy(Path source, Path target) throws IOException {
    try (InputStream in = Files.newInputStream(source);
         OutputStream out = Files.newOutputStream(target)) {
        byte[] buffer = new byte[8192];
        int count;

        while ((count = in.read(buffer)) != -1) {
            out.write(buffer, 0, count);
        }
    }
}

这里 count 表示本次实际读入的字节数。一次 read(buffer) 不保证填满整个数组,可能只返回一部分;只有返回 -1 才表示后面没有数据。因此不要用"读到的长度等于缓冲区长度"判断是否结束,也不要只调用一次就认为整个文件已经读完。

字节流和字符流的 read() 不要混为一谈

InputStream.read() 面向字节,返回 0..255 或 -1。字符流 Reader.read() 面向字符,返回 0..65535 的字符值或 -1。两者都用 int,是因为返回类型还要容纳 EOF 标记;但表示的数据单位不同。

如果处理的是文本,应使用 Reader 或 InputStreamReader 并明确字符集。不要把每个字节直接强转成 char 来解码 UTF-8 等多字节编码。

**记住这三点:**单字节读取先用 int 判断 -1;缓冲区读取按返回的实际字节数写出;文本解码交给字符流和明确的字符集。

参考:Java SE 21 InputStream.read() 文档、Java SE 21 Reader.read() 文档。

相关推荐
luobobo8961 小时前
支付回调验签连续失败三天,最后发现是网关的时间戳单位问题
java
Nuanyt1 小时前
LeetCode Hot100 刷题笔记 · 普通数组专题
java·笔记·算法·leetcode
cfm_29143 小时前
Leaf-segment号段模式
java
Wang's Blog3 小时前
Java 项目实战: 交友项目 - 发布圈子动态:数据库表和接口文档介绍
java·数据库·交友
paopaokaka_luck3 小时前
智慧电玩店管理系统(空闲机台随机分配、游玩时长概率模拟、积分自动结算、积分兑换闭环、 ECharts经营分析、 腾讯地图选址)
java·人工智能·mysql·echarts·推荐算法
LMT流氓兔3 小时前
第五单元——第9课:防止同一次操作重复执行
java·服务器·数据库·算法·ai·langchain
OxYGC3 小时前
Spring 面经系列 · 第 6 篇:Spring MVC 请求全流程、父子容器与零配置原理
java·spring·mvc
code2cat3 小时前
Java高级篇之JDBC:连接数据库,完成查询、更新与事务
java·开发语言·数据库
bksczm3 小时前
Redis数据结构之string
java·redis·mybatis