更新3
进步!我写了一个带三个参数的CMD脚本:sqlite3cipher.exe
的绝对路径testdb
的绝对路径statements.sql
的绝对路径
脚本所做的就是执行命令
path\to\sqlite3cipher.exe path\to\testdb < path\to\statements.sql
这个脚本是从我的java代码中调用的。它就像一个符咒!至少所有文件都在主目录的文件夹中。将文件放在
C:\Program Files
的子文件夹中不起作用,因此可能存在权限问题,我必须与管理员一起解决。更新2
我在主目录中创建了一个虚拟sql文件。代码现在应该从中读取sql文件,并将数据库文件写入主目录。
再次在命令中省略
cmd /c
将读取和写入sql文件的第一行,但在这之后将停止(整个程序的执行将停止)。执行命令,包括
cmd /c
读取和写入sql文件的每一行,但一旦达到eof(在这种情况下,当然不会写入任何内容),我将再次收到Access denied
消息。更新1
将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
将打印用法。这里有一个练习: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()
不太熟悉,但我从阅读中了解到,在windows(测试服务器正在运行windows 8)上启动命令解释器需要cmd /c
作为命令的一部分。执行时,此代码在命令行(通过进程的流)返回
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
时得到的输出是相同的。这就是执行停止的地方。TL;博士
在命令行上直接执行就像一个符咒
从Java执行的完全相同的命令不起作用
由
cmd /c
预先准备的命令(显然应该是这样)和进程的InputStream
和OutputStream
的用法不起作用:Access denied
我不知道下一步该怎么办,所以我真心希望有人能帮我。
最佳答案
所以我用更新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
调用testdb
,并从statements.sql
调用重定向输入。关键是脚本的位置和exe的位置不是系统文件夹。
如果所有这些标准都得到满足,那么一切都像一种魅力。
关于java - 用Java执行外部程序会返回“访问被拒绝”或停止执行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24675308/