gpt4 book ai didi

Java 和 MySQL 控制台 REPL

转载 作者:行者123 更新时间:2023-11-29 02:42:19 25 4
gpt4 key购买 nike

我需要编写一个 Java 代码来创建一个运行 MySQL 控制台命令的 shell,并且可以保留交互式 session ,直到它被故意破坏。

为了模拟它,这是我的代码。

    ProcessBuilder pb;
pb = new ProcessBuilder(
"cmd.exe","/c","c://xampp//mysql//bin//mysql","-uroot");

Process p = pb.start();

OutputStream stdout = p.getOutputStream();
InputStream stdin = p.getInputStream();

BufferedReader reader = new BufferedReader(new InputStreamReader(stdin));
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdout));

boolean written = false;
while(true) {
System.out.println("loop... ");

writer.write("show databases;\r\n\r\n");
writer.flush();
writer.newLine();
writer.newLine();
writer.flush();
writer.close(); //If not close, it cannot produce result

String line;
line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
}

问题是,代码只运行一次,因为在循环中调用了 writer.close()。但如果我不调用 writer.close(),它永远不会响应。

我怎样才能实现我的目标?

最佳答案

您的问题来自 line = reader.readLine()。在找到完整的行之前它不会返回,这由输出流中的换行符指示。但是当你处理mysql的输出时,你得到的不是完整的一行,而是一个“提示符”,比如

mysql> _

此外,它将从不返回null,直到它正在读取的进程终止或以其他方式关闭它的输出流。所以你不能将它用作循环终止条件。相反,您应该逐个字符地阅读流,寻找您提交的命令已完成的指示。

我没有安装 mysql,因为我安装了 sqlite3,所以我创建了一个脚本,它使用测试数据库“sql”启动它,查询表 t1(单个文本列,两个行),并打印输出。重复 3 次。

ProcessBuilder pb = new ProcessBuilder("/usr/bin/sqlite3", "sql");
Process p = pb.start();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));

// Don't use a BufferedReader; it waits for '\n' characters.
InputStreamReader isr = new InputStreamReader(p.getInputStream());

// Our own "Buffered Reader" workspace
StringBuilder sb = new StringBuilder();

// Execute 3 times only ...
for(int i=0; i<3; i++) {

System.out.println("Command: select * from t1;");
bw.write("select * from t1;\n");
bw.write(".print !-DONE-!\n");
bw.flush();

System.out.println("Result:");
// Repeat until magic phrase in read buffer
while (true) {

// Read characters one at a time...
char ch = (char) isr.read();

// Do our own newline processing.
if (ch == '\n') {
String line = sb.toString(); // Buffer to string
sb.setLength(0); // ... and clear buffer

if (line.equals("!-DONE-!"))
break;

System.out.println(line);
} else {
sb.append(ch);
}
}
System.out.println();
}

jshell pb.java 的输出:

Command: select * from t1;
Result:
Hello world
Goodbye world!

Command: select * from t1;
Result:
Hello world
Goodbye world!

Command: select * from t1;
Result:
Hello world
Goodbye world!

| Welcome to JShell -- Version 9
| For an introduction type: /help intro

jshell> _

似乎 stdin 来自另一个进程,而 stdout 去往另一个进程,我的 sqlite3 拒绝发出 sqlite>stdout 上提示。这让我很伤心,在与各种设置和命令行选项进行了一个小时的斗争之后,我放弃了,只是添加了一个打印命令来打印神奇的单词 !-DONE-!。输出处理寻找这个魔法词,并跳出结果读取循环。

如果你能弄清楚让 mysqlstdout 上输出 mysql> _ 提示符所需的魔法咒语,那么你的中断条件将在非换行路径中,类似于:

      } else {
sb.append(ch);
if (sb.length() == 7 && sb.toString().equals("mysql> ")) {
sb.setLength(0);
break;
}
}

关于Java 和 MySQL 控制台 REPL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48974994/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com