Why aren't my Windows batch files processing w

2019-03-03 09:17发布

问题:

I have 2 folders, each containing dozens of batch files (*.bat).

The batch files containing text similar to either

del /f/q F:\MEDIA\IMAGE99\2010\270\z\4034\123.tif > nul
del /f/q F:\MEDIA\IMAGE99\2010\266\z\3025\456.tif > nul
del /f/q F:\MEDIA\IMAGE99\2010\267\z\3025\789.tif > nul
del /f/q F:\MEDIA\IMAGE99\2010\286\z\9025\101.tif > nul
del /f/q F:\MEDIA\IMAGE99\2010\272\z\6029\112.tif > nul
del /f/q F:\MEDIA\IMAGE99\2010\258\z\4034\134.tif > nul

or

rmdir /q F:\MEDIA\IMAGE99\2010\270\z\4034
rmdir /q F:\MEDIA\IMAGE99\2010\266\z\3025
rmdir /q F:\MEDIA\IMAGE99\2010\267\z\3025
rmdir /q F:\MEDIA\IMAGE99\2010\286\z\9025
rmdir /q F:\MEDIA\IMAGE99\2010\272\z\6029
rmdir /q F:\MEDIA\IMAGE99\2010\258\z\4034

In Java, I list each batch File in each folder, and cycle through the list, executing each batch file as follows:

public static boolean batch(File file) {

    boolean handled = false;
    Process process = null;
    try {

        process = Runtime.getRuntime().exec("cmd /c start " + file);
        handled = process.waitFor() == 0;

    } catch (Exception ex) {
        // handling removed for example purposes
    } 

    return handled;
}

After the method returns, I delete the batch file.

The problem is, none of the commands within my batch files run (the files and folders I request deleted or removed are not), and the Java process simply continues and deletes batch file itself.

The batch files are located in folder d:\working\spaced folder\purge\batch_files\

Having written this out, I suspect my problem is that I'm passing a file path with a space in it to the exec() method.

Is my suspicion correct? If so, how do I resolve it? If not, what might the problem be?

I'm going to look into Java: Execute /cmd /c start path-with-spaces\program.exe now that I've considered it.


UPDATE

Per the comments below, I've changed my code, but now the output hangs at waitFor() and the batch file is not being processed (the files I request deleted are still there).

Code:

        String commandString = "cmd /c \"" + file +"\"";
        logger.info("COMMAND " + commandString);
        process = Runtime.getRuntime().exec(commandString);
        logger.info("WAITING FOR " + commandString);
        handled = process.waitFor() == 0;
        logger.info("HANDLED " + commandString + " = " + handled);

Output:

COMMAND : cmd /c "d:\working\spaced folder\purge\deleteBatch\F_140.bat"
WAITING FOR : cmd /c "d:\working\spaced folder\purge\deleteBatch\F_140.bat"

回答1:

now the output hangs at waitFor()

When you start an external process from Java using Runtime.exec you must read any output that the process produces otherwise the process may block (source: JavaDocs for java.lang.Process).

Use ProcessBuilder instead, and call redirectErrorStream to merge the standard output and error streams, then read all the content from process.getInputStream() until you reach EOF. Only then is it safe to call waitFor.

ProcessBuilder will also help with the spaces issue, as you must split up the command line into individual words yourself

ProcessBuilder pb = new ProcessBuilder("cmd", "/c", file.getAbsolutePath());


回答2:

Code of successful solution used, based on Ian Roberts' answer:

Uses Apache Commons-IO

package com.stackoverflow.windows;

import java.io.File;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.NullOutputStream;

public class Command {

    private Command() {}

    public static boolean batch(File file) {

        boolean handled = false;
        Process process = null;
        ProcessBuilder pb = new ProcessBuilder("cmd", "/c", file.getAbsolutePath());
        pb.redirectErrorStream(true);

        try {

            process = pb.start();
            IOUtils.copy(process.getInputStream(), new NullOutputStream());
            handled = process.waitFor() == 0;

        } catch (Exception ignore) {

            // Only throws an IOException we're trying to avoid anyway, 
            // and an expected InterruptedException 
            // handled will be false

        } finally {

            if (process != null) {

                IOUtils.closeQuietly(process.getInputStream());
            }           
        }

        return handled;
    }
}