【问题标题】:Use Java ProcessBuilder to interact with SQLite shell使用 Java ProcessBuilder 与 SQLite shell 交互
【发布时间】:2014-01-23 21:09:39
【问题描述】:

我使用以下两种方法手动运行sqlite3.exe。

  1. 如果我在 Windows 命令行中键入“sqlite3.exe test.db”,sqlite3 会进入它的交互式 shell,我可以在其中输入各种命令。

  2. 如果我输入第三个 SQL 参数,例如。 'SQLite.exe test.db "SELECT * FROM clients"',sqlite3不交互运行,而是通过stdout输出请求的数据。

我想通过 java 代码与 shell 中的提示进行交互(第一种情况)。

使用以下快速 Java 代码,我可以非交互方式运行 SQLite3.exe(第二种情况)。

    char[] readBuffer=new char[1000];

    //Third parameter in constructor is the select statement
    ProcessBuilder pBuilder=new ProcessBuilder(pathToSQLite3exe, "test.db",
     "\"SELECT * FROM clients"\" ); 

    pBuilder.directory(new File(pathToExeFolder));
    pBuilder.redirectErrorStream(true);

    Process process=pBuilder.start();

    InputStreamReader reader=new InputStreamReader(process.getInputStream());

    int charCount;

    while (true)
    {
        charCount=reader.read(readBuffer);
        if (charCount>0)
        {
            System.out.print(new String(readBuffer,0,charCount));
        }
        else
        {
            break;
        }
    }

上面的工作按预期工作,但是如果我在 ProcessBuilder 构造函数中省略第三个参数(select 语句),程序会永远暂停,大概是在 reader.read() 语句处,因为没有要读取的字符。我想 sqlite3.exe 确实进入了交互模式,但是输入流不是由 shell 的标准输出提供的。我希望看到交互式提示文本并能够将命令写入输出流。

Java 和 ProcessBuilder 可以做到这一点吗?

谢谢。

【问题讨论】:

    标签: java sqlite processbuilder


    【解决方案1】:

    来自Processjavadoc:http://docs.oracle.com/javase/7/docs/api/java/lang/Process.html

    默认情况下,创建的子进程没有自己的终端或控制台。它的所有标准 I/O(即 stdin、stdout、stderr)操作都将被重定向到父进程,在那里可以通过使用 getOutputStream()、getInputStream() 和 getErrorStream() 方法获得的流来访问它们。父进程使用这些流向子进程提供输入并从子进程获取输出。

    您可以从 Process 获取 OutputStream 并将您通常在交互式运行 SqlLite 时直接在控制台中输入的内容写入其中。

    OutputStream os = process.getOutputStream();
    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os));
    bw.write("SELECT * FROM clients;");
    bw.newLine();
    bw.flush();
    

    然后像你已经做的那样读取 InputStream,它应该有你在交互式运行 SqlLite 时通常会看到的输出。

    【讨论】:

    • 谢谢!按照您的建议,我获得了查询结果,但是输出不会像手动运行 shell 时那样以 SQLite> 提示终止;那么如何确定何时从输入流中读取了所有数据?我想到了一种可能的解决方法...我附加了另一个 SELECT 语句,它返回一个已知的唯一值(波浪号),从而标记数据的结尾。有没有更好的办法?该死,我没有足够的声望来投票赞成你的答案。
    • 我不确定最好的方法是什么。如果你正在做的工作我会说坚持下去,即使它有点hacky。
    猜你喜欢
    • 2014-02-10
    • 2019-10-30
    • 2015-05-25
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多