gpt4 book ai didi

java - 用Java执行外部程序会返回“访问被拒绝”或停止执行

转载 作者:塔克拉玛干 更新时间:2023-11-02 20:03:54 25 4
gpt4 key购买 nike

更新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);
}
}

其中 progfDbfSqlScriptFile类型,分别表示 sqlite3cipher.exetestdbstatements.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预先准备的命令(显然应该是这样)和进程的 InputStreamOutputStream的用法不起作用: 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/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com