字节流和字符流无物理界限,仅逻辑分工不同:字节流(inputstream)以byte为单位处理原始数据,不涉及编码;字符流(reader)以char为单位,依赖编码规则将字节转换为unicode字符, inputstreamreader是连接二者的桥梁。

字节流和字符流没有物理界限,只有逻辑分工。它们操作的都是同一份底层数据(比如硬盘上的文件、网络传来的字节),区别在于“怎么看”和“怎么用”。
数据单位决定视角不同
InputStream 每次读一个 byte(8位),它不关心这8位是字母、汉字的一部分,还是图片像素值——一律当原始数字处理。
Reader 每次读一个 char(16位 Unicode 字符),它必须把底层字节按某种编码规则“拼出来”,比如把 UTF-8 中连续3个字节组合成一个‘中’字。
编码是隐含的分水岭
这个“拼”的动作,就是字符流存在的核心依据:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- InputStream 不做任何编码转换,你用它读中文文本,得到的是乱码字节数组,需手动 new String(bytes, "UTF-8") 才能还原
- Reader(如 InputStreamReader 或 FileReader)内部封装了编码逻辑,创建时指定 charset,后续 read() 直接返回正确 char 值
- 没指定编码或指定错误,字符流也会乱码;反过来,用 Reader 去读 jpg 文件,某些字节序列会被强行转成无效字符,导致内容损坏
类名与继承关系是明确标识
Java 的 IO 类设计用命名和继承划清了这条线:
- 所有字节输入流都继承自 InputStream,类名带 Stream(如 FileInputStream、BufferedInputStream)
- 所有字符输入流都继承自 Reader,类名以 Reader 结尾(如 FileReader、BufferedReader、InputStreamReader)
- InputStreamReader 是特例:它本身是 Reader,但构造时必须传入 InputStream,是唯一显式暴露“字节→字符”转换过程的桥梁类
实际文件类型是选择依据
不是靠文件后缀判断,而是看你要处理的内容本质:
- 要复制一张 PNG 图片、解压 ZIP、反序列化对象 → 必须走 InputStream,跳过编码,保真字节
- 要逐行读取 log 文件、解析 JSON 字符串、写入 Java 源码 → 应该用 Reader,让编码转换自动发生,避免手动处理 byte[] 和 String 的来回转换
- 如果数据源只有字节流(如 Socket.getInputStream()、URLConnection.getInputStream()),又需要读文本,就用 InputStreamReader 包一层,并明确指定 charset










