Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Problem with copy files using cmd in Java

I'm trying to copy a bunch of files with a specific extension from one folder to another using the copy command, heres wat im doing,

 String[] command = new String[3];
 command[0] = "cmd";
 command[1] = "/c";
 command[2] = "copy C:\\output\\html\\*.txt C:\\output\\";

 ProcessBuilder copyFiles = new ProcessBuilder(command);
 p = copyFiles.start();
 p.waitFor();

the thing is, this code works fine for files less than some 5 or so, but just stops responding wen the number of files are more (even for 15 files) !! and the files are not copied either!! I dont know what the problem is, will be glad if someone could help! :)

like image 200
Hari Krishna Avatar asked May 02 '11 16:05

Hari Krishna


1 Answers

You're not reading the output the copy command is generating.

When spawning a child process using ProcessBuilder, output generated by your child process gets written to a buffer. If this buffer isn't read from, it eventually fills up. When it fills up, the copy command can't write any more to it and so is blocked by the operating system. It is then forced to wait until space is made in the buffer by reading from it.

I ran your code with 20 files and I found that it did indeed hang.

One way to solve your problem is to redirect the output from copy to NUL. Most of the output from copy is a list of all the files it has copied, which you probably don't care too much for. To do this redirection, modify the line that assigns to command[2] to the following:

command[2] = "copy C:\\output\\html\\*.txt C:\\output\\ >NUL 2>NUL";

However, if there is a problem copying files, you might not know about it if you do this.

Alternatively, you can read the output that the copy command generates. The following code sends it to System.out, but you can easily send it elsewhere or completely ignore it if you wish:

String[] command = { "cmd", "/c", "copy C:\\output\\html\\*.txt C:\\output\\" };
ProcessBuilder copyFiles = new ProcessBuilder(command);
copyFiles.redirectErrorStream(true);
p = copyFiles.start();

// The InputStream we get from the Process reads from the standard output
// of the process (and also the standard error, by virtue of the line
// copyFiles.redirectErrorStream(true) ).
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
do {
    line = reader.readLine();
    if (line != null) { System.out.println(line); }
} while (line != null);
reader.close();

p.waitFor();

I gave each approach a quick test with the same 20 files and neither approach hung.

EDIT: You might also want to try a 'hybrid' approach, by throwing away what copy writes to standard output (e.g. the list of files it's copying) but using the second approach to read in what it writes to standard error (e.g. error messages). To do this, you'd add the >NUL, which redirects the standard output of copy to NUL, but you wouldn't add the 2>NUL, since that redirects standard error to NUL.

like image 57
Luke Woodward Avatar answered Nov 01 '22 20:11

Luke Woodward