我正在尝试使用 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;
}
有人能告诉我我做错了什么吗?
我成功地做到了这一点,方法是放弃与正在运行的进程交互的想法,而是调用 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();
}
}