进展!我写了一个CMD脚本,它有三个参数:
sqlite3cipher.exe
testdb
statements.sql
所有脚本都执行命令
path\to\sqlite3cipher.exe path\to\testdb < path\to\statements.sql
从我的Java代码中调用此脚本。它就像一个魅力!至少所有文件都驻留在我的主目录中的文件夹中。将文件放在C:\Program Files
子文件夹中并不起作用,因此可能存在我必须与管理员协商的权限问题。
我在我的主目录中创建了一个虚拟SQL文件。代码现在应该从中读取SQL文件并将数据库文件写入我的主目录。
再次省略命令中的cmd /c
会从SQL文件中读取和写入第一行,但在此之后停止(整个程序的执行停止)。
执行包含cmd /c
的命令读取和写入SQL文件的每一行但是一旦达到EOF(当然没有任何内容会被写入)我再次收到Access denied
消息。
将skarist的评论考虑在内以下命令(省略cmd /c
,因为执行exe文件不是必须的)
String cmdForRuntime = "\"" + prog.getAbsolutePath() + "\" \"" + fDb.getAbsolutePath() + "\"";
拼写出来的看起来像
"C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb"
不会产生任何输出。代码也停止执行,所以我认为I / O有问题吗?
为了编码数据库,我想在Java命令行上执行sqlite3cipher.exe
。
我遇到了各种方法的相当不同的结果。首先是设置(注意这是一个测试环境,现在没有任何关于文件所在位置的更改):
sqlite3cipher.exe
位于C:\Program Files\Apache Software Foundation\bin\
空文件testdb
位于C:\Program Files\Apache Software Foundation\pages\dbdir\
包含SQL语句statements.sql
的文件与testdb
位于同一文件夹中
在命令行上执行sqlite3cipher.exe -help
打印用法。这是一个exerpt:
C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe [OPTIONS] FILENAME [SQL]
FILENAME is the name of an SQLite database. A new database is created if the file does not previously exist.
在命令行上执行"C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb" < "C:\Program Files\Apache Software Foundation\pages\dbdir\statements.sql"
具有所需的效果:testdb
现在是根据通过statements.sql
放入的SQL语句的加密数据库。
现在在Java中,我的代码如下所示:
String cmdForRuntime = "cmd /C \"" + prog.getAbsolutePath() + "\" \"" + fDb.getAbsolutePath() + "\" < \"" + fSqlScript.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec( cmdForRuntime );
BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
while ((s = stdIn.readLine()) != null) {
logger.info("OUTPUT FROM PROG: " + s);
}
if (process.waitFor() == 0) {
logger.info("Process finished");
}
else {
logger.error("Error!");
// Get input streams
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Standard error: ");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
其中prog
,fDb
和fSqlScript
的类型为File
,分别代表sqlite3cipher.exe
,testdb
和statements.sql
。
我对Process.execute()
并不精通,但我从阅读中得到的是cmd /c
作为命令的一部分在Windows上是必需的(测试服务器运行的是Windows 8)为了启动命令解释器。
执行时,此代码在命令行上返回Access denied
(通过进程的流)。在命令行上执行此确切命令(包括cmd /c
)会直接返回相同的结果:Access denied
。即使我以管理员身份启动命令行。
让cmd /c
离开命令(因为它之前没有在命令行上工作),我得到的信息是too many options
。
经过进一步调查,我了解到这个问题是由<
运算符引起的,该运算符在命令中用于重定向输入。 exec()
方法无法将<
识别为运营商,建议您使用该流程OutputStream
。所以我将代码更改为:
String cmdForRuntime = "cmd /c \"" + prog.getAbsolutePath() + "\" \"" + fDb.getAbsolutePath() + "\"";
Process process = Runtime.getRuntime().exec( cmdForRuntime );
BufferedWriter bufferedwriter = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader br = new BufferedReader(new FileReader(fSqlScript.getAbsolutePath()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
String fileInput = br.readLine();
while (fileInput != null) {
bufferedwriter.write(fileInput);
while ((s = stdIn.readLine()) != null) {
logger.info("OUTPUT FROM PROG: " + s);
}
fileInput = br.readLine();
}
if (process.waitFor() == 0) {
logger.info("Process finished");
}
else {
logger.error("Error!");
// Get input streams
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Standard error: ");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
据我所知,阅读外部程序打印的内容非常重要,因此它不会阻止或停止工作。这就是为什么我从statements.sql
(通过BufferedReader br
)读取一行并将其写入流程OutputStream
的原因。然后我读了程序将打印出来的内容(记录该输出)。如果没有(左)阅读,我会阅读statements.sql
的下一行。这将重复进行,直到没有任何内容可以从所述文件中读取。
如果我执行此代码,我的记录器将记录以下内容:
INFO Executing command: cmd /c "C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb"
ERROR Error!
Standard error:
Access denied
在这种情况下,代码至少会终止,从而导致空文件testdb
。在另一种方法中,我在命令中保留cmd
但跳过了/c
,导致以下输出:
INFO Executing command: cmd "C:\Program Files\Apache Software Foundation\bin\sqlite3cipher.exe" "C:\Program Files\Apache Software Foundation\pages\dbdir\testdb"
INFO OUTPUT FROM PROG: Microsoft Windows [Version 6.3.9600]
INFO OUTPUT FROM PROG: (c) 2013 Microsoft Corporation. Alle Rechte vorbehalten.
INFO OUTPUT FROM PROG:
输出与在命令行中键入cmd
时得到的输出相同。执行停止的地方。
cmd /c
作为前缀(显然应该是这样),并且流程InputStream
和OutputStream
的使用不起作用:Access denied
我不确定下一步该做什么,所以我真诚地希望有人可以帮助我。
答案 0 :(得分:1)
所以我用更新3中提到的解决方法解决了这个问题。
我的Java代码现在看起来像这样(除了cmdForRuntime
变量之外,它应该与开头时的代码几乎相同,当我问这个问题时):
try {
File fDb = new File(this.inputDirectory + File.separator + dbName);
String cmdForRuntime = "\"" + cmdScript.getAbsolutePath() + "\"" + " " + // the script to be executed
"\"" + prog.getAbsolutePath() + "\"" + " " + // sqlite3cipher.exe
"\"" + fDb.getAbsolutePath() + "\"" + " " + // testdb
"\"" + fSqlScript.getAbsolutePath() + "\""; // statements.sql
logger.info("Executing command: " + cmdForRuntime );
Process process = Runtime.getRuntime().exec( cmdForRuntime );
BufferedReader stdIn = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
while ((s = stdIn.readLine()) != null) {
logger.info("OUTPUT FROM PROG: " + s);
}
if (process.waitFor() == 0) {
logger.info("Process finished");
}
else {
logger.error("!!!! error !!!!");
// Get input streams
BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
System.out.println("Standard error: ");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
}
catch(Exception ioe) {
ioe.printStackTrace();
}
cmdForRuntime
会读到这样的内容(我会省略路径,唯一会增加混淆):
"SQLiteCipher.cmd" "sqlite3cipher.exe" "testdb" "statements.sql"
脚本的内容如下所示:
%1 %2 < %3
这会调用带有参数sqlite3cipher.exe
的{{1}}和来自testdb
的重定向输入。
严重的是脚本的位置以及exe的位置不是系统文件夹。
如果满足所有这些标准,一切都像魅力一样。
答案 1 :(得分:0)