I have created a simple java program to open an excel file and write data to it, once the data is written I then proceed to open the file to view the spreadsheet:
String[] cmdarray=new String[]{"cmd.exe","/c","C:\\Users\\Jason\\Documents\\*******\\********\\******.xls"};
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(cmdarray);
as part of the learning curve I then try to close the file 10 secs later with:
process.destroy();
but this isn't closing the window.
Can anyone point out where I am going wrong? Thank you.
private static void OpenExcel() throws IOException {
//Find the File and open it
String[] cmdarray=new String[]{"cmd.exe","/c","C:\\Users\\Jason\\Documents\\*********\\*********\\********.xls"};
Runtime runTime = Runtime.getRuntime();
Process process = runTime.exec(cmdarray);
try{
//Delay
TimeUnit.SECONDS.sleep(10);
}catch (InterruptedException e) {
e.printStackTrace();
//Handle exception
}
//Close Excel
System.out.println("Closing Excel");
process.destroy();
}
}
One of the reason could be well-known JDK bug:
The fundamental problem here is that, unlike Unix, Windows does that
maintain parent-child relationships between processes. A process can
kill its own immediate children, but unless you make other
arrangements to obtain the information, can't kill any
'grand-children' because it has no way of finding them.
You can try with direct execution of Excel, not via cmd:
Runtime.getRuntime().exec("C:\\full\\path\\to\\excel.exe C:\\file.xls");
Related
How do I run an external command (via a shell) from a Java program, such that no redirection takes place, and wait for the command to end? I want the file descriptors of the external program to be the same as those of the Java program. In particular I do not want the output to be redirected to a pipe that the Java program is reading. Having the Java program relay the output is not a solution.
This means that a plain invocation of java.lang.Runtime.exec is not the solution. I presume that java.lang.ProcessBuilder is involved, but how do I specify that output and error streams must be the same as the calling Java process?
class A {
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("echo", "foo");
/*TODO: pb.out = System.out; pb.err = System.err;*/
Process p = pb.start();
p.waitFor();
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
}
}
(This may or may not be the right approach.)
In other words, I'm looking for Java's system, but all I can find is (roughly) popen.
Here's an example of a situation where relaying cannot work: if the subprocess writes to both stdout and stderr and the Java program is relaying, then the Java program has no way to know the order of the write calls in the subprocess. So the order of the output on stdout and stderr from the Java program will be observably different if the two streams end up in the same file. Mixing stdout and stderr is of course not a solution because the caller may want to keep them separate.
While I think this question is of general interest, a Linux-specific solution would solve my immediate problem.
This is the intent of ProcessBuilder.redirectError/redirectOutput which were introduced in Java 7. Using Redirect.INHERIT will make the child process share stderr/stdout with the Java process:
class A {
public static void main(String[] args) {
try {
ProcessBuilder builder = new ProcessBuilder("echo", "foo");
builder.redirectError(ProcessBuilder.Redirect.INHERIT);
builder.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process p = builder.start();
p.waitFor();
} catch (Exception e) {
System.err.println(e);
System.exit(1);
}
}
}
You might take a look at the NuProcess project. Disclaimer: I wrote it. It provides non-blocking I/O from spawned processes. You still have to relay in Java (you receive callbacks), but because it is using epoll() in the case of Linux, I would expect it to preserve the order of the underlying program. Only a single thread is epoll()'ing the pipes so you won't get any thread scheduling order issues.
I'm 100% order would be preserved on MacOS X, or any BSD variant, because it uses a kqueue which is definitely ordered. Anyway, you might want to give it a shot, it's trivial to code and test.
You can't. By default all standard I/O of the child process are redirected to the parent process (the jvm running your java program).
from the javadoc of the Process class:
By default, the created subprocess does not have its own terminal or
console. All its standard I/O (i.e. stdin, stdout, stderr)
operations will be redirected to the parent process, where they can be
accessed via the streams obtained using the methods getOutputStream(),
getInputStream(), and getErrorStream(). The parent process uses these
streams to feed input to and get output from the subprocess. Because
some native platforms only provide limited buffer size for standard
input and output streams, failure to promptly write the input stream
or read the output stream of the subprocess may cause the subprocess
to block, or even deadlock.
I've been working on in a swing application. I've a JFrame having some buttons and fields.
On some button click event,I'm opening an exe from my current directory. Everything works fine.
try {
Runtime.getRuntime().exec(System.getProperty("user.dir") +
"\\Upgrade\\Upgrade.exe");
} catch (IOException ex) {
ex.printStacktrace();
}
this.dispose(); // disposing my current java file.
But what i need is to exit the java code after opening the exe file.
Anyone help to deal this.?
Can you try making it a process, then waiting for that process to finish before exiting, like so:
class SO {
public static void main(String args[]) {
try {
Process proc = Runtime.getRuntime().exec("your command");
proc.waitFor(); //Wait for it to finish
System.exit(0);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Executing an application from java using Runtime.exec() is a source of well known problems. Like waiting for a Process to finish, but not consuming the data from the stream buffers is a sure way for you application to hang.
I would suggest you use a library like Apache Common Exec to handle this.
I worked on a project a while back where we used Runtime.exec() to launch a process that would eventually extract files over existing files. All worked well except on one machine used for staging - it would just hang. It turned out on that staging machine, someone had set the date/time back so it looked liked the new files being extracted where older than the existing one, causing the external process to generate a warning message for each, overflowing the error buffer - which our application was not consuming!
Why do I get this error when I run this program? This occurs after random iterations. Usually after the 8000th iteration.
public static void main(String[] args)
{
FileWriter writer = null;
try
{
for(int i = 0; i < 10000; i++)
{
File file = new File("C:\\Users\\varun.achar\\Desktop\\TODO.txt");
if(file.exists())
{
System.out.println("File exists");
}
writer = new FileWriter(file, true);
writer.write(i);
System.out.println(i);
writer.close();
if(!file.delete())
{
System.out.println("unable to delete");
}
//Thread.sleep(10);
//writer = null;
//System.gc();
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if(writer != null)
{
try
{
writer.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
After the exception occurs, the file isn't present. That means the it is deleting, but FIleWriter tries to acquire the lock before that, even though it isn't a multi threaded program. Is it because the Windows isn't deleting the file fast enough, and hence the FileWriter doesn't get a lock? If so, then file.delete() method returns before windows actually deletes it?
How do i resolve it, since i'm getting a similar issue during load testing my application.
EDIT 1: Stacktrace:
java.io.FileNotFoundException: C:\Users\varun.achar\Desktop\TODO.txt (Access is denied)
at java.io.FileOutputStream.openAppend(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:192)
at java.io.FileOutputStream.<init>(FileOutputStream.java:116)
at java.io.FileWriter.<init>(FileWriter.java:61)
EDIT 2 : Added file.exists() and file.delete conditions in the program. and the new stacktrace:
7452
java.io.FileNotFoundException: C:\Users\varun.achar\Desktop\TODO.txt (Access is denied)
at java.io.FileOutputStream.openAppend(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:192)
at java.io.FileWriter.<init>(FileWriter.java:90)
at com.TestClass.main(TestClass.java:25)
EDIT 3 Thread dump
TestClass [Java Application]
com.TestClass at localhost:57843
Thread [main] (Suspended (exception FileNotFoundException))
FileOutputStream.<init>(File, boolean) line: 192
FileWriter.<init>(File, boolean) line: 90
TestClass.main(String[]) line: 24
C:\Users\varun.achar\Documents\Softwares\Java JDK\JDK 6.26\jdk\jre\bin\javaw.exe (09-Nov-2011 11:57:34 PM)
EDIT 4 : Program runs successfully on different machine with same OS. Now how do i ensure that the app with run successfully in the machine it is deployed in?
On any OS you can have only a certain number of open files/threads at a stretch. You seem to be hitting your OS limit. Try setting file to null inside the loop.
If I understand your stack trace correctly, the exception is coming when trying to create a new FileWriter. It's impossible to know the reason without investigating a bit further.
Return values may tell something. Especially, check what File.delete() returns.
Before trying to create new FileWriter, check what File.exists() returns.
If the previous delete() returns true and the exists() right after it also returns true, in a single-threaded program, then it's indeed something weird.
Edit: so it seems that deletion was successful and the file didn't exist after that. That how it's supposed to work, of course, so it's weird why FileWriter throws the exception. One more thought, try checking File.getParentFile().canWrite(). That is, do your permissions to write to the directory somehow disappear.
Edit 2:
Don't get the error on a different machine with the same OS. Now how do i make sure that this error won't come in the app where it'll be deployed?
So far you have one machine that works incorrectly and one that works correctly. Maybe you could try it on even more machines. It's possible that the first machine is somehow broken and that causes errors. It's amazing how often digital computers and their programs (I mean the OS and Java, not necessarily your program) can be just a "little bit broken" so that they work almost perfectly almost all of the time, but fail randomly with some specific hardware & use case - usually under heavy load - similar to how incorrect multi-threaded programs can behave. It doesn't have to be your fault to be your problem :-)
Frankly, the only way to make sure that errors won't come up in machine X is to run the program on machine X. Unusual stuff such as creating and deleting the same file 8000 times in rapid succession is prone to errors, even though it "should" work. Computers, operating systems and APIs are not perfect. The more unusual stuff you do, the more often the imperfections will realize themselves, because unusual usage is generally less thoroughly tested than everyday operations.
I have had the same issue, a java program (single threaded) that opens, deleted then re-opens the same file continuously.
On some windows systems we get the same issue as reported here, on Linux, Solaris, and various other windows systems it works fine.
Traceing the program with SysInternals Process Monitor (now MS) its clear the delete is done first, at the OS level, and clear the subsequent open fails with PENDING DELETE status.
So there seems to be some slight delay at the OS/NTFS/Disk level before the file is actually deleted, and that seems to be the cause of the random failure in our case.
As a workaround, I changed the .delete() call to instead just write over the top of it new FileWriter(file) and that seems to be working.
The problem did not occur on all systems, one specific model that would always fail, all be it after not fixed number of loops, was a Windows 7 / Dell Lattitude E6420 with WD Smartdrive, whereas my Windows 7 / Dell precision M4600 (with solid state drive) or T3400 with Linux I have never had the issue.
Cheers - Mark
It may be a long shot, but, can you try to work with a file that is NOT directly sitting on the Desktop. Instead of:
"C:\\Users\\varun.achar\\Desktop\\TODO.txt"
Try:
"C:\\Users\\varun.achar\\SomeOtherDirectory\\TODO.txt"
OS may be killing you here with all the Desktop hooks...
EDIT based on the comments:
Are there any scheduled jobs running on the "bad" machine?
Instead of debugging the environment, do you have a sys admin to do that?
Does this work on a clean Windows install? [95% chance it will]
Since the root cause seems to be environment, instead of solving a Windows configuration problem, would you be able to move forward with other tasks, and leave it to someone who keeps the list of discrepancies between the systems?
Can you conditionally try to write to the file ?
Using file.exists and then writing to it, so you can potentially avoid any other issues. Hard to say from this exception.
http://download.oracle.com/javase/6/docs/api/java/io/File.html#exists()
Could you also post a thread dump at that point, just to debug it further.
Please flush the writer, before writing again.
These are the scenerios you should handle before deleting a file http://www.java2s.com/Code/Java/File-Input-Output/DeletefileusingJavaIOAPI.htm
at least check for return value in your program.
Thanks folks for help me out but this is how it got resolved finally.
public static void main(String[] args)
{
FileWriter writer = null;
try
{
for(int i = 0; i < 10000; i++)
{
File file = new File("C:\\tenant-system-data\\abc.txt");
if(!file.getParentFile().canWrite())
{
System.out.println("parent file error");
}
if(file.exists())
{
System.out.println("File exists");
}
int count = 0;
while(count++ < 5)
{
try
{
file.createNewFile();
break;
}
catch(IOException e)
{
try
{
Thread.sleep(100);
}
catch(InterruptedException e1)
{
e1.printStackTrace();
}
}
}
writer = new FileWriter(file, true);
writer.write(i);
System.out.println(i);
writer.close();
if(!file.delete())
{
System.out.println("unable to delete");
}
//Thread.sleep(10);
//writer = null;
//System.gc();
}
}
catch(IOException e)
{
e.printStackTrace();
}
finally
{
if(writer != null)
{
try
{
writer.close();
}
catch(IOException e)
{
e.printStackTrace();
}
}
}
}
I just had the same problem (FileWriter & Access Denied).
My guess for the reason: Windows 7 had put a lock on the file because a preview of the file content was shown in an Explorer window (the file was selected in the window).
Solution: I de-selected the file in the Explorer window. And the IOException was gone.
You have delete permission in the directory but not create permission.
I am writing this question which is related to my previous topic:
Run bat file from java code to get desired result in txt file - no can do :(
In a shortcut: i wrote a program in java that runs a bat file. This bat file runs TestComplete8 script that performs desktop application test. After test is finished, bat file generates file called result.txt and prints information about test to it.
I'm stuck with another issue right now: Now from my java code i would like to wait until the bat run is finished. I do that by looping until the file called result.txt exists. Not the nicesest solution i guess but I thought it could work, also tried different solutions. What happens is that it will loop fine and wait until file exists, but testcomplete doesn't perform the test. It is very strange, because testcomplete runs, i can see that test starts, my AUT starts as well, but than nothing happens. Testcomplete is waiting for any object and doesn't click anywhere just waits until predefined time for action runs out. When i run the test without any waiting done in code, everything is fine. I just don't understand why nothing happens during the test when waiting is enabled and why it works fine when i just remove any do - while or waitFor(), or even i tried running it in seperate threads. :(
I have a feeling that it may be somehow related to the OS and have something to do with processes as it runs something like a bat as process and than bat runs it's child process as testcomplete or sth like that.
Thanks for any answers
Source code as asked:
Right now i was trying a solution with modified bat file:
#ECHO OFF
"C:\Program Files (x86)\Automated QA\TestComplete 8\Bin\TestComplete.exe" "C:..." /r /p:projname PathToApp="C:\...p" Login=... Password=B1 /t:"KeywordTests|..." /exit
and the code to run and wait in latest version is:
new Thread(new Runnable() {
public void run() {
File file = new File("D:\\");
int exitValue = -1;
try {
Process process = Runtime.getRuntime().exec(batch, null, file);
while (true) {
try {
exitValue = process.exitValue();
System.out.println(exitValue);
break;
} catch (IllegalThreadStateException e) {
// e.printStackTrace();
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
System.out.println("Waiting for process...");
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
The most likely cause, without knowing more about the problem, is a common one faced when launching external processes from Java. When launching an external process three streams are created between the parent and child process, input, output, error.
You can liken these to System.in, System.out and System.err. If the parent process (Java) does not actively consume the data on the out and error streams the child process may block as the OS will reach a buffer limit on the stream and prevent any more being written until it is consumed. This is quite likely if your script writes to standard out or standard error.
I would recommend using apache commons-exec to handle Java process launching.
Here's a code sample that I know works.
CommandLine commandLine = new CommandLine( "TestComplete8.bat" );
commandLine.addArgument( ... );
commandLine.addArgument( ... );
DefaultExecutor executor = new DefaultExecutor();
executor.setExitValue( 0 );
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
executor.setStreamHandler( new PumpStreamHandler( outputStream, errorStream ) );
try
{
executor.execute( commandLine );
}
catch ( ExecuteException e )
{
// TODO: ...
}
catch ( IOException e )
{
// TODO: ...
}
Then you can examine the output/error streams if you wish when execute returns.
In my program, I need to run a external command in a Ubuntu environment (ntpdate) using java. Currently my code looks like this:
Runtime rt = Runtime.getRuntime();
byte[] readBuffer = new byte[131072];
// Exec a process to do the query
Process p = null;
try {
p = rt.exec("ntpdate -q " + ip);
} catch (Exception ex) {
ex.printStackTrace();
}
if(p!= null){
try {
Thread.sleep(1000);
} catch (Exception e) {
}
// Read the input stream, copy it to the file
InputStream in = p.getInputStream();
try {
int count = 0, rc;
while ((rc = in.read(readBuffer, count, readBuffer.length - count)) != -1) {
count += rc;
if (count >= readBuffer.length) {
p.destroy();
break;
}
}
p.destroy();
result = processOutput(readBuffer, count);
} catch (IOException ex) {
ex.printStackTrace();
}
p.destroy();
This code need to be ran simultaneously on multiple threads in order to maximize performance (I need to test a list of 1.000.000 addresses using ntpdate). However, it runs very slowly, barely consuming machine processing. What am I doing wrong? How could I make this more efficient?
The same problem arises when trying to execute "dig" using .exec(), so I doubt it is because of the specific program being called. Is there some restriction in using Runtime.exec() in a multi Threaded environment?
Is Java the most appropriate approach here? Perhaps this would be better in a shell script, which calls ntpdate in the background multiple times? I'm not sure what benefit you're getting from this code snippet by doing this in Java.
What are you doing with the InputStream from the process?
A bash script could do this like:
for ip in #...IP list
do
ntpdate -q $ip > $ip.txt &
done
Why are you waiting for 1 second at each time ?
try {
Thread.sleep(1000);
} catch (Exception e) {
}
This will do nothing but slowing the execution of your application.
Not sure why it's slow but you need to do a lot more to close your resources. Runtime.exec() needs quite a bit of care and attention to avoid hang-ups and leaking of file descriptors.
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
Are you sure the issue isn't ntpdate? If ntpdate is just sitting there waiting for a server response and has a large timeout value, then your application is going to sit there too.
Try calling ntpdate with a timeout of 0.2 and see if it makes a difference.
Also, as you're opening streams in your code, you definitely want to explicitly .close() them when you're done. Otherwise it might not happen until a GC which could be a very long time away.
I think I found the solution, and that is that there is no solution using java's Runtime.exec(). The problem seems to be that all calls to start a process are synchronized. Indeed, if you start each process alone (via synchronization) you get the exact same result of starting all processes together.
Are there any alternatives to exec? Otherwise, I will need to get some solution without linux's ntpdate...
I notice that both of the commands you tried involve network round-trips. How is the speed if you call something like echo or cat instead?