使用Java进程运行MacOS SQLite查询

问题描述 投票:0回答:1

我正在尝试使用 Java 的 Process 类在 MacOS 照片数据库上运行查询(给定 UUID,原始 HEIC 文件名是什么?)。我能够从终端命令行加载数据库并成功运行查询。但是当我启动 Process 时,我无法从其 BufferedInputReader 收集响应。

这是我正在执行的代码:

String uuid = "\"838C3AD6-D5E8-4340-8DD5-0EB8244D\"";
SqliteProcess sp = new SqliteProcess(10000, uuid);
sp.start();
try {
   sp.join(10000);
} catch (InterruptedException ex) {
}
System.out.println("UUID: " + uuid + ", Filename: " + sp.filename);

这是课程:

public class SqliteProcess extends Thread {

    private Process proc = null;
    private long timeout;
    private String uuid;
    public String filename = "";

    public SqliteProcess(long timeout, String uuid) {
        super();
        this.timeout = timeout;
    }

    @Override
    public void run() {
        ProcessBuilder builder = new ProcessBuilder("sqlite3", "/Users/ferdberfle/Pictures/Photos Library.photoslibrary/database/Photos.sqlite"); // or whatever your command is
        try {
            proc = builder.start();
        } catch (IOException ex) {
            System.out.println(ex.getLocalizedMessage());
        }
        String s = commandAndResponse("SELECT ZMASTER FROM ZASSET WHERE ZUUID = \"" + uuid + "\";");
        System.out.println("RESPONSE: " + s);
        if (s.isEmpty()) {
            sqlEnd();
            return;
        }
        filename = commandAndResponse("SELECT ZORIGINALFILENAME FROM ZCLOUDMASTER WHERE Z_PK = \"" + s + "\";");
        System.out.println("RESPONSE: " + filename);
        sqlEnd();
    }

    private void sqlEnd() {
        try {
            BufferedWriter bw = proc.outputWriter();
            bw.write(".exit");
            bw.newLine();
            bw.flush();
        } catch (IOException ex) {
        }
    }

    private String commandAndResponse(String c) {
        if (!c.isEmpty()) {
            try {
                BufferedWriter bw = proc.outputWriter();
                bw.write(c);
                bw.newLine();
                bw.flush();
            } catch (IOException ex) {
                return "";
            }
        }
        String buff = "";
        BufferedReader br = proc.inputReader();
        String line;                     // This is where the code freezes. No exception,
        try {                            // but it never comes back from br.readLine().
            while ((line = br.readLine()) != null) {
                buff += line;
            }
        } catch (IOException ex) {
        }
        return buff;
    }

有人能告诉我我做错了什么吗?

java macos sqlite process
1个回答
0
投票

我成功地做到了这一点,方法是放弃与正在运行的进程交互的想法,而是调用 Sqlite 进程两次 - 进行两次单独的查找。

String s = app.filenameFromUUID("838C3AD6-D5E8-4340-8CC5-0EB8244D8890");
System.out.println("ANSWER: " + s);

public String filenameFromUUID(String uuid) {
        long timeout = 10000L;
        String fname = "file:///" + System.getProperty("user.home") + "/Pictures/Photos Library.photoslibrary/database/Photos.sqlite?mode=ro";
        SqliteProcess p1 = new SqliteProcess(timeout, "sqlite3", fname,
                "SELECT ZMASTER FROM ZASSET WHERE ZUUID = \"" + uuid + "\"");
        p1.startAndWait();
        String sm = p1.answer.trim();
        SqliteProcess p2 = new SqliteProcess(timeout, "sqlite3", fname,
                "SELECT ZORIGINALFILENAME FROM ZCLOUDMASTER WHERE Z_PK = " + sm);
        p2.startAndWait();
        return p2.answer;
    }

public class SqliteProcess extends Thread {

    private final String command[];
    private Process proc;
    private final long timeout;

    public int exitCode = 0;
    public boolean completed = false;
    public boolean exception = false;
    public boolean timed_out = false;
    public String answer = "";
    public String errMsg = "";

    private InputStream is;

    public SqliteProcess(long timeout, String... args) {
        this.timeout = timeout;
        command = new String[args.length];
        System.arraycopy(args, 0, command, 0, command.length);
    }
    
    public SqliteProcess startAndWait() {
        start();
        try {
            join();
        } catch (InterruptedException ex) {
        }
        return this;
    }
    
    @Override
    public void run() {
        ProcessBuilder builder = new ProcessBuilder();      // Shell command with "/c" to terminate immediately
        builder.command(command);
        builder.directory(new File(System.getProperty("user.home")));
        try {
            proc = builder.start();
        } catch (IOException ex) {
            errMsg = ex.getLocalizedMessage();
            int pos = errMsg.indexOf("Error message: ");
            if (pos >= 0) {
                errMsg = errMsg.substring(pos + 15);
            }
            exception = true;
            return;
        }
        is = proc.getInputStream();
        try {
            proc.waitFor(timeout, TimeUnit.MILLISECONDS);
        } catch (InterruptedException ex) {
            errMsg = "Command interrupted ";
            exception = true;
            return;
        }
        completed = !proc.isAlive();
        if (!completed) {
            errMsg = "Command timeout";
            timed_out = true;
        }
        if (is != null) {
            answer = getReply(proc);
        }
        exitCode = proc.exitValue();
    }

    private static String getReply(Process proc) {
        ByteArrayOutputStream input = new ByteArrayOutputStream();
        byte buffer[] = new byte[4096];
        int length;
        InputStream is = proc.getInputStream();
        try {
            while ((length = is.read(buffer)) > 0) {
                input.write(buffer, 0, length);
            }
        } catch (IOException ex) {
            return "";
        }
        return input.toString().trim();
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.