Java - Unable to delete temporary output file for Process on Windows

98 Views Asked by At

On Windows, I am creating subprocess via java.lang.ProcessBuilder. On trying to cleanup the process and its standard output log file if my caller function is interrupted, I get error "The process cannot access the file because it is being used by another process". I am ensuring that I destroy the subprocess first and then delete the logfile.

Question - Are there any best practices when cleaning up processes and log files that are platform agnostic?

Here is a reproducible example for Windows.

Below snippet is creating a subprocess.

public class UndeletableFileExample {
    public static void func() throws IOException {
        ProcessBuilder pb = null;
        Path stdout = null;
        Process p = null;
        long bufferTimeSecs = 30L;
        try {
            stdout = Files.createTempFile("example", ".log");
            pb = new ProcessBuilder("loop.cmd");
            pb.redirectErrorStream(true);
            pb.redirectOutput(stdout.toFile());
            p = pb.start();
            p.waitFor(bufferTimeSecs, TimeUnit.SECONDS);
            p.destroy();
            p.waitFor(bufferTimeSecs, TimeUnit.SECONDS);
            p.destroyForcibly();
            String out = Files.readString(stdout);
            int exitcode = p.exitValue();
            if(exitcode != 0) {
                throw new RuntimeException("Exited with code " + exitcode);
            }
            System.out.println(out);
        }
        catch(InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("interrupted!");
        }
        finally {
            if(p != null) {
                p = p.destroyForcibly();
                while(p.isAlive()); // Is this while loop a potential problem?
                System.out.println(p.exitValue());
            }
            if(stdout != null) {
                Files.delete(stdout);
            }
        }
    }
}

Below snippet is for the for-loop file "loop.cmd". It will print numbers from 1 till 1e5. This takes a good 20-30 seconds on my machine.

FOR /L %%i IN (1,1,100000) DO echo %%i

Below snippet is for the main program that does the simulation.

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread() {
            @Override
            public void run() {
                try {
                    UndeletableFileExample.func();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        t.start();
        Thread.sleep(2000L);
        t.interrupt();
        t.join();
    }
}

I also have access to a MacOS machine. I didn't encounter any problem there in cleaning up the process and the logfile on a thread interrupt.

The loop example for MacOS changes to -

for i in `seq 1 1000000`; do echo $i; done

The exact error on Windows is as follows -

Exception in thread "Thread-0" java.lang.RuntimeException: java.nio.file.FileSystemException: <...>\example1234.log: The process cannot access the file because it is being used by another process. 
0

There are 0 best solutions below