Spring Boot中如何让BufferedInputStream不关闭流就返回捕获内容?
问题:不关闭流时读取MySQL Shell进程的输出
我有一个Spring Boot REST应用,包含两个端点:
- 第一个端点通过类似
mysql -u root的命令启动MySQL Shell进程 - 第二个端点接收查询命令并写入进程的输入流(对应
Process的OutputStream)
启动MySQL Shell进程的代码
ProcessBuilder builder = new ProcessBuilder(commands); builder.redirectErrorStream(true); process = builder.start(); // 注意:进程的输出流对应我们的输入流,用来读取进程返回的结果 out = process.getInputStream(); // 进程的输入流对应我们的输出流,用来向进程发送命令 in = process.getOutputStream();
执行查询命令的代码
byte[] commandBytes = command.getBytes(Charset.defaultCharset()); in.write(commandBytes, 0, commandBytes.length); in.flush();
尝试读取结果的代码
int no = out.available(); if (no > 0) { int n = out.read(buffer, 0, Math.min(no, buffer.length)); System.out.println(new String(buffer, 0, n)); }
问题在于out.available()始终返回0,只有关闭in(进程的输入流)后,out.available()才会返回可读取的字节数并允许读取,但这不符合需求——我需要保持进程存活,多次执行查询并读取结果。
是否可以在不关闭流的情况下读取MySQL Shell的输出结果?
我注意到BufferedInputStream内部依赖FileInputStream和FileChannel,但没找到不关闭输出流时捕获结果的方法。
解决方案
1. 问题本质
available()仅能返回当前操作系统缓冲区中已就绪、可无阻塞读取的字节数,但MySQL交互Shell在执行命令后,不会主动将输出立刻刷入缓冲区——它会保持输出缓冲状态,直到进程退出或输出达到阈值才会释放数据,再加上available()本身的局限性,导致你无法通过它检测到待读取的结果。
另外,同步调用读取方法会阻塞主线程,严重影响REST接口的响应性,这也是必须解决的问题。
2. 正确实现:异步读取+提示符判断
MySQL交互Shell执行命令后,会先输出查询结果,再输出提示符(如mysql>)。我们可以通过单独线程异步监听进程输出流,持续读取数据,直到检测到提示符标记,以此判断当前查询的结果已读取完成。
示例代码:
// 启动异步线程持续读取进程输出 new Thread(() -> { BufferedReader reader = new BufferedReader(new InputStreamReader(out)); String line; try { while ((line = reader.readLine()) != null) { // 根据提示符判断当前查询是否结束 if (line.trim().endsWith("mysql>")) { // 这里可以添加结果完成的标记逻辑,比如通知主线程 System.out.println("当前查询结果读取完成"); } else { // 处理单条查询结果行 System.out.println("查询结果:" + line); } } } catch (IOException e) { e.printStackTrace(); } }).start(); // 执行查询的逻辑保持不变,注意要加换行符确保命令被执行 byte[] commandBytes = (command + "\n").getBytes(Charset.defaultCharset()); in.write(commandBytes); in.flush();
3. 关键注意事项
- 必须用异步线程读取:同步读取会阻塞REST接口的请求线程,导致接口无响应。
- 适配提示符:不同版本的MySQL Shell提示符可能有差异(如
[root@localhost] mysql>),需要根据实际环境调整判断逻辑。 - 弃用
available():该方法不适合交互进程的场景,阻塞式读取(在异步线程中)才是可靠的方式。 - 资源清理:应用关闭时需主动销毁
Process、关闭所有流,避免资源泄漏。
内容的提问来源于stack exchange,提问作者Mykyta Hupalo
相关产品推荐
相关产品推荐

