I'm using process = Runtime.getRuntime().exec(cmd,null,new File(path));
to execute some SQL in file (abz.sql)
Command is:
"sqlplus "+ context.getDatabaseUser() + "/"
+ context.getDatabasePassword() + "#"
+ context.getDatabaseHost() + ":"
+ context.getDatabasePort() + "/"
+ context.getSid() + " #"
+ "\""
+ script + "\"";
String path=context.getReleasePath()+ "/Server/DB Scripts";
It is executing that file but not getting exit. Hence I tried using:
Writer out = new OutputStreamWriter(process.getOutputStream());
out.append("commit;\r\n");
out.append("exit \r\n");
System.out.println("---------"+out);
out.close();
This it complete block that I m using:
if(context.getConnectionField()=="ORACLE")
{
String cmd=
"sqlplus "+ context.getDatabaseUser() + "/"
+ context.getDatabasePassword() + "#"
+ context.getDatabaseHost() + ":"
+ context.getDatabasePort() + "/"
+ context.getSid() + " #"
+ "\""
+ script +"\"";
String path=context.getReleasePath()+ "/Server/DB Scripts";
process = Runtime.getRuntime().exec(cmd,null,new File(path));
out = new OutputStreamWriter(process.getOutputStream());
out.append("commit;\r\n");
out.append("exit \r\n");
System.out.println("---------"+out);
out.close();
Integer result1 = null;
while (result1 == null) {
try {
result1 = process.waitFor();
}
catch (InterruptedException e) {}
}
if(process.exitValue() != 0)
return false;
return true;
}
The code shown fails to read the error stream of the Process. That might be blocking progress. ProcessBuilder was introduced in Java 1.5 and has a handy method to redirectErrorStream() - so that it is only necessary to consume a single stream.
For more general tips, read & implement all the recommendations of When Runtime.exec() won't.
I can see a few issues here. The version of 'exec' that you are using will tokenize the command string using StringTokenizer, so unusual characters in the password (like spaces) or the other parameters being substituted are accidents waiting to happen. I recommend switching to the version
Process exec(String[] cmdarray,
String[] envp,
File dir)
throws IOException
It is a bit more work to use but much more robust.
The second issue that there are all kinds of caveat about whether or not exec will run concurrently with the Java process (see http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Process.html). So you need to say which operating system you're on. If it does not run concurrently then your strategy of writing to the output stream cannot work!
The last bit of the program is written rather obscurely. I suggest ...
for (;;) {
try {
process.waitFor();
return process.exitValue() == 0;
} catch ( InterruptedException _ ) {
System.out.println( "INTERRUPTED!" ); // Debug only.
}
}
This eliminates the superfluous variable result1, eliminates the superfluous boxing and highlights a possible cause of endless looping.
Hope this helps & good luck!
Related
I use IntelliJ. I have a class that manages student grades. It can edit files, which I have a new .temp file being written, and renamed. Then the old file gets deleted. On my laptop (mac) this works fine, but on my desktop (windows) everything works, but the old file is not deleted, and temp is not renamed.
Below is my method to edit the files:
private static void editStuGrade() throws Exception {
System.out.println("Enter a course grade you want to change (q1,q2,q3,mid,final): ");
String editInput = command.next();
System.out.println("Enter a new score: ");
String newGrade = command.next();
Path p = Paths.get(System.getProperty("user.dir"),"src","Assignment1", student.name + ".txt");
File inputFile = new File(p.toString());
FileInputStream inputStream = new FileInputStream(inputFile);
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader reader = new BufferedReader(inputStreamReader);
File outputFile = new File(p + ".temp");
FileOutputStream outputStream = new FileOutputStream(outputFile);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream);
BufferedWriter writer = new BufferedWriter(outputStreamWriter);
if (editInput.equalsIgnoreCase("q1")) {
writer.write(student.name + "," + student.id + "," + newGrade + "," + student.quiz2
+ "," + student.quiz3 + "," + student.midterm + "," + student.finalTest);
writer.close();
} else if (editInput.equalsIgnoreCase("q2")) {
writer.write(student.name + "," + student.id + "," + student.quiz1 + "," + newGrade
+ "," + student.quiz3 + "," + student.midterm + "," + student.finalTest);
writer.close();
} else if (editInput.equalsIgnoreCase("q3")) {
writer.write(student.name + "," + student.id + "," + student.quiz1 + "," + student.quiz2
+ "," + newGrade + "," + student.midterm + "," + student.finalTest);
writer.close();
} else if (editInput.equalsIgnoreCase("mid")) {
writer.write(student.name + "," + student.id + "," + student.quiz1 + "," + student.quiz2
+ "," + student.quiz3 + "," + newGrade + "," + student.finalTest);
writer.close();
} else if (editInput.equalsIgnoreCase("final")) {
writer.write(student.name + "," + student.id + "," + student.quiz1 + "," + student.quiz2
+ "," + student.quiz3 + "," + student.midterm + "," + newGrade);
writer.close();
}
inputFile.delete();
outputFile.renameTo(new File(p.toString()));
System.out.println("Successful.");
}
Windows is a special snowflake. Unlike other OSes (or rather, Windows File System, unlike other file systems) does not let you delete any open files, and does not let you rename or delete directories of they contain any open files. In contrast to other OSes which don't mind at all; files on disk are merely 'pointers', and any process that opens a file also gets a pointer. The file isn't truly removed from disk until all pointers are gone, so, you can just delete files - if that file is still open, no problem - as long as it is the file doesn't disappear. It's very similar to java garbage collection in that way.
But not so on windows.
Your code has a bug in it - you aren't managing your resources. This is resulting in the files being open, and then you try to delete them - this works on non-windows filesystems but isn't allowed on windows - you can't delete files even if you're the very process that still has them open.
Resources MUST be closed, and the responsibility to do this lies on you. Given that code can exit in many ways (not just 'by running to the end of a method', but also: With return, by throwing an exception, by using break or continue for flow control, etc). Therefore, trying to write code by hand that ensures your resource is closed for all possible exit paths is annoying and error prone, so, don't. Use java's language features:
Do not EVER open a resource unless you do so in a try-with block.
Looks like this:
try (var outputStream = new FileOutputStream(outputFile)) {
// outputStream exists here and can be interacted with as normal
}
No matter how code flow 'exits' that try block, the resource is closed automatically once it does. This is good - not just because this lets you delete those files, but also because every process gets a limited number of files they get to open, so if you fail to close, any non-trivial app will soon hard-crash due to having too many open files.
What are resources? The javadoc will tell you, and use common sense. most InputStream and OutputStreams are - any type that implements AutoClosable tends to be. If you new X() them up you definitely have to close them. If you're invoking a method that sounds like it 'makes' the resource (example: socket.getInputStream or Files.newInputStream), you have to close them.
Use try () {} to do this.
Once you do so, you can delete these files just fine, even on windows.
I need to transform over 500k pdf files to png (with the sufficient density) tpo be able to treat it later (reading a QR code embedded in the pdf). The files normally don't surpass 200kb
I tried using magick to convert it (first using convert and then mogrify), but figured that it will take days to finish and figured that maybe doing it with threads was better. So i implemented a little app in java that creates n threads and executes in the windows shell (Runtime.getRuntime().exec()) a builded command with the file and target and all that.
Problem is it kills my pc. Apparently magick uses multithreads for processing each images and since some of those are taken by the script I did, it takes longer and takes resources that the jvm wouldnt normally take. Here is my code:
public class SuperPdfToPngConverter {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("Setting Up Environment...");
System.out.println("Reading existing files...");
// To change according to our needs
String targetFolder = "D:\\Digest";
// Execution parameters
ArrayList<String> myList = getTodoList(targetFolder);
ArrayList<String> rejected = new ArrayList<String>();
System.out.println("I've found " + myList.size() + " documents pending to be converted.");
System.out.println(" Treating files... ");
int count = 1;
ExecutorService executor = Executors.newFixedThreadPool(16);
for (String fileId : myList) {
System.out.println("Queueing file " + count + ", " + fileId);
Runnable worker = new WorkerThread(fileId, targetFolder, true, 150);
executor.execute(worker);
//rejected.add(fileId);
count++;
}
executor.shutdown();
while (!executor.isTerminated()) {
}
System.out.println("Finished");
System.out.println(
"Treated " + (count - 1) + " documents; ");
}
And the working part on each thread goes like this:
#Override
public void run() {
System.out.println(Thread.currentThread().getName()+" Start. File = "+ fileName);
processCommand();
System.out.println(Thread.currentThread().getName()+" End.");
}
private void processCommand() {
String fileNamePng = fileName.replace(".pdf", ".png");
String cmd = "magick convert -density " + density + "x" + density + " " + fileName + " " + fileNamePng;
System.out.println(cmd);
try {
Runtime.getRuntime().exec(cmd, null, new File(targetPath));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Document " + fileName + " processed.");
}
I was wondering what can I do to make this run a little bit faster and stable. I don't care much about how long it takes (as long as its reasonable).
Do you think my approach is good? Is it better if I use a library rather than a tool like magick?
Thank you for your insight.
I'm using mencoder to split files and I'd like to turn this into an Object Oriented approach, if possible, using Java or similar, for example. But I'm not sure the best way, so I leave it in the open. Here is what I need:
I have an excel file with start times and end times, and I need to extract out the appropriate clips from a video file. In the terminal (I'm on Mac OS X) I've had success using, for example:
mencoder -ss 0 -endpos 10 MyVideo.avi -oac copy -ovc copy -o Output.avi
Which creates the video Output.avi by clipping the first 10 seconds of the video MyVideo.avi.
But, like I said, I want to make it so that a program reads in from an excel file, and calls this mencoder command multiple times (over 100) for each of the start times and end times.
I know how to read in the excel file in Java, but I'm not sure it is best to call this command from Java. Plus, I'd like to be able to see the output of mencoder (because it prints out a nice percentage so you know about how much longer a single command will take). Is this type of thing feasible to do in a shell script? I would really like to use Java if possible, since I have many years of experience in Java and no experience in shell scripting.
UPDATE
Here is what I've tried in Java, but it freezes at in.readLine()
File wd = new File("/bin");
System.out.println(wd);
Process proc = null;
try {
proc = Runtime.getRuntime().exec("/bin/bash", null, wd);
}
catch (IOException e) {
e.printStackTrace();
}
if (proc != null) {
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
out.println("cd ..");
out.println("pwd");
String video = "/Users/MyFolder/MyFile.avi";
String output = "/Users/MyFolder/output.avi";
int start = 0;
int end = 6;
String cmd = "mencoder -ss " + start +
" -endpos " + end +
" " + video + " -oac copy -ovc copy -o " + output;
out.println(cmd);
try {
String line;
System.out.println("top");
while ((line = in.readLine()) != null) {
System.out.println(line);
}
System.out.println("end");
proc.waitFor();
in.close();
out.close();
proc.destroy();
}
catch (Exception e) {
e.printStackTrace();
}
}
I'm not quite sure about mencoders multicore-capabilities, but I think with Java you can use Multiple Threads to get the maximal power of all cpu-cores.
You shouldn't use Runtime like your using it.
When using Runtime, you should not run bash and send commands via inputstream like when you are typing commands on a terminal.
Runtime.getRuntime().exec("mencoder -ss " + start +
" -endpos " + end +
" " + video + " -oac copy -ovc copy -o " + output);
To get the Output, you can use the inputStream
http://docs.oracle.com/javase/1.4.2/docs/api/java/lang/Runtime.html#exec%28java.lang.String,%20java.lang.String[],%20java.io.File%29
With this command you can also set the Workingdirectory where your command is executed.
I also prefer the version with the String[] as parameters. It's much more readable, than the a concatenated String.
I used the following code for getting the motherboard serial number. But I got the o/p Result is empty. What mistake did I make in this code?
File file = File.createTempFile("realhowto",".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);
String vbs =
"Set objWMIService = GetObject(\"winmgmts:\\\\.\\root\\cimv2\")\n"
+ "Set colItems = objWMIService.ExecQuery _ \n"
+ " (\"Select * from Win32_BaseBoard\") \n"
+ "For Each objItem in colItems \n"
+ " Wscript.Echo objItem.SerialNumber \n"
+ " exit for ' do the first cpu only! \n"
+ "Next \n";
fw.write(vbs);
fw.close();
Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
BufferedReader input =
new BufferedReader
(new InputStreamReader(p.getInputStream()));
String line;
while ((line = input.readLine()) != null) {
result += line;
}
if(result.equalEgnoreCase(" ") {
System.out.println("Result is empty");
} else {
System.out.println("Result :>"+result);
}
input.close();
}
I can confirm that the VBS side of this works fine on my machine; however, the output I got was:
MB-1234567890
which doesn't seem particularly unique or helpful. Still, if this is what you're after, try the following. Paste the VBS into a .vbs file and run it using cscript <myfile>.vbs:
Set objWMIService = GetObject("winmgmts:\\.\root\cimv2")
Set colItems = objWMIService.ExecQuery _
("Select * from Win32_BaseBoard")
For Each objItem in colItems
Wscript.Echo objItem.SerialNumber
exit for ' do the first cpu only!
Next
If that works, it's the Java that's at fault (and I suspect it's not capturing the process output for some reason). Otherwise, it's the VBS script failing you.
There are some more hints and tips on this thread which might give you some different strategies.
Process p = Runtime.getRuntime().exec("wmic baseboard get serialnumber");
or
Process p = Runtime.getRuntime().exec("wmic /node:"HOST" bios get serialnumber");
instead of HOST , give ur hostname, which can be arrived at typing hostname in cmd prompt.
I have a Java application that I'm about to begin to use Web Start to deploy. But a new demand has made me rethink this, as I'm now required to add a piece of functionality that allows the end user to select whether or not they'd like to run this program on startup (of Windows, not cross-platform). But I'd still like to shy away from making this run as a service. Is there any way that this can be accomplished using Web Start, or should I explore other options to deploy this? Thanks in advance.
It actually works to put a this in the jnlp-file:
<shortcut online="true">
<desktop/>
<menu submenu="Startup"/>
</shortcut>
But that still would only work with English windows versions. German is "Autostart", Spanish was "Iniciar" I think. So it causes basically the same headache as the way via the IntegrationService.
I have not tried it, but I wonder if you could use the new JNLP IntegrationService in combination with the javaws command line program. The idea being to programmatically create a shortcut in the Windows startup group (although that location is dependent on specific Windows version).
To get around the language problem for the Startup folder just use the registry. Here is some code that should work. This calls reg.exe to make registry changes.
public class StartupCreator {
public static void setupStartupOnWindows(String jnlpUrl, String applicationName) throws Exception {
String foundJavaWsPath = findJavaWsOnWindows();
String cmd = foundJavaWsPath + " -Xnosplash \"" + jnlpUrl + "\"";
setRegKey("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", applicationName, cmd);
}
public static String findJavaWsOnWindows() {
// The paths where it will look for java
String[] paths = {
// first use the JRE that was used to launch this app, it will probably not reach the below paths
System.getProperty("java.home") + File.separator + "bin" + File.separator + "javaws.exe",
// it must check for the 64 bit path first because inside a 32-bit process system32 is actually syswow64
// 64 bit machine with 32 bit JRE
System.getenv("SYSTEMROOT") + File.separator + "syswow64" + File.separator + "javaws.exe",
// 32 bit machine with 32 bit JRE or 64 bit machine with 64 bit JRE
System.getenv("SYSTEMROOT") + File.separator + "system32" + File.separator + "javaws.exe",};
return findJavaWsInPaths(paths);
}
public static String findJavaWsInPaths(String[] paths) throws RuntimeException {
String foundJavaWsPath = null;
for (String p : paths) {
File f = new File(p);
if (f.exists()) {
foundJavaWsPath = p;
break;
}
}
if (foundJavaWsPath == null) {
throw new RuntimeException("Could not find path for javaws executable");
}
return foundJavaWsPath;
}
public static String setRegKey(String location, String regKey, String regValue) throws Exception {
String regCommand = "add \"" + location + "\" /v \"" + regKey + "\" /f /d \"" + regValue + "\"";
return doReg(regCommand);
}
public static String doReg(String regCommand) throws Exception {
final String REG_UTIL = "reg";
final String regUtilCmd = REG_UTIL + " " + regCommand;
return runProcess(regUtilCmd);
}
public static String runProcess(final String regUtilCmd) throws Exception {
StringWriter sw = new StringWriter();
Process process = Runtime.getRuntime().exec(regUtilCmd);
InputStream is = process.getInputStream();
int c = 0;
while ((c = is.read()) != -1) {
sw.write(c);
}
String result = sw.toString();
try {
process.waitFor();
} catch (Throwable ex) {
System.out.println(ex.getMessage());
}
if (process.exitValue() == -1) {
throw new Exception("REG QUERY command returned with exit code -1");
}
return result;
}
}