根本原因是字符编码不匹配,外部进程默认UTF-8输出而InputStreamReader使用平台默认编码;应显式指定StandardCharsets.UTF_8创建读取器,避免依赖默认构造函数。

Java中用InputStreamReader读取Process.getInputStream()时出现乱码,根本原因是字符编码不匹配——外部进程输出的字节流编码与InputStreamReader默认使用的平台编码(如Windows上是GBK)不一致,而多数现代命令行工具(如Linux/macOS命令、Python脚本、Node.js程序)默认按UTF-8输出。
明确指定UTF-8编码创建InputStreamReader
不要依赖默认构造函数,必须显式传入StandardCharsets.UTF_8(推荐)或"UTF-8"字符串:
-
错误写法:
new InputStreamReader(process.getInputStream())(使用系统默认编码) -
正确写法:
new InputStreamReader(process.getInputStream(), StandardCharsets.UTF_8) - 若需兼容旧版JDK(new InputStreamReader(process.getInputStream(), "UTF-8"),但要注意捕获
UnsupportedEncodingException
确保外部进程实际输出UTF-8
仅Java端设UTF-8不够,还需确认子进程本身以UTF-8编码输出。常见情况包括:
- Linux/macOS终端命令一般默认UTF-8,基本无需干预
- Windows CMD默认GBK,可改用
chcp 65001 && your-command临时切换到UTF-8 - Python脚本:添加
sys.stdout.reconfigure(encoding='utf-8')(Python 3.7+)或设置环境变量PYTHONIOENCODING=utf-8 - Java子进程:通过
ProcessBuilder设置environment().put("JAVA_TOOL_OPTIONS", "-Dfile.encoding=UTF-8")
统一处理输入/错误流并避免死锁
乱码常伴随读取阻塞甚至死锁——尤其当子进程同时写stdout和stderr且未及时消费时。建议:
立即学习“Java免费学习笔记(深入)”;
- 对
getInputStream()和getErrorStream()都用UTF-8的InputStreamReader包装 - 用独立线程分别读取两路流,或使用
BufferedReader逐行读取(readLine()自动处理换行符) - 避免先读完一个流再读另一个,防止子进程因缓冲区满而挂起
验证编码是否生效的简单方法
在读取前加一句调试输出,确认字节内容与预期一致:
- 用
InputStream原始读取前几个字节(如process.getInputStream().readNBytes(10)),查看十六进制值是否符合UTF-8规则(如中文“你好”UTF-8编码为E4 BD A0 E5 A5 BD) - 打印
System.getProperty("file.encoding"),确认当前JVM默认编码,避免误以为它就是子进程编码 - 在目标系统上手动执行同一命令,重定向到文件:
your-command > out.txt,再用文本编辑器以UTF-8打开验证原始输出


















