2

This is somewhat befuddling. The following batch snippet results in copying both files:

xcopy "C:\Source\Spaces1 [ ].txt" "C:\Target\" /Y
xcopy "C:\Source\Spaces2 [  ].txt" "C:\Target\" /Y

And the following Java snippet using streams also results in copying both files:

public static void main(final String args[]) throws IOException
{
    final File source1 = new File("C:\\Source", "Spaces1 [ ].txt");
    final File target1 = new File("C:\\Target", "Spaces1 [ ].txt");
    fileCopy(source1, target1);

    final File source2 = new File("C:\\Source", "Spaces2 [  ].txt");
    final File target2 = new File("C:\\Target", "Spaces2 [  ].txt");
    fileCopy(source2, target2);
}

public static void fileCopy(final File source, final File target) throws IOException
{
    try (InputStream in = new BufferedInputStream(new FileInputStream(source));
            OutputStream out = new BufferedOutputStream(new FileOutputStream(target));)
    {
        final byte[] buf = new byte[4096];
        int len;
        while (0 < (len = in.read(buf)))
        {
            out.write(buf, 0, len);
        }
        out.flush();
    }
}

However, in this snippet, one of the files is NOT copied (the one with double spaces is skipped):

public static void main(final String args[]) throws Exception
{
    final Runtime rt = Runtime.getRuntime();
    rt.exec("xcopy \"C:\\Source\\Spaces1 [ ].txt\" \"C:\\Target\\\" /Y").waitFor();

    // This file name has two spaces in a row, and is NOT actually copied
    rt.exec("xcopy \"C:\\Source\\Spaces2 [  ].txt\" \"C:\\Target\\\" /Y").waitFor();
}

What's the deal? This is going to be used to copy files from who-knows-what source, where people can type in anything they like. Files names are sanitized, but who sanitizes for two spaces in a row? What am I missing here?

Currently using Java 8, but Java 6 and 7 give the same results.

Gray
  • 115,027
  • 24
  • 293
  • 354
JonathanDavidArndt
  • 2,518
  • 13
  • 37
  • 49

1 Answers1

1

It's all in the Javadoc.

Runtime#exec(String) delegates to Runtime#exec(String,null,null)

exec(String,null,null) delegates to exec(String[] cmdarray,envp,dir)

Then

More precisely, the command string is broken into tokens using a StringTokenizer created by the call new StringTokenizer(command) with no further modification of the character categories. The tokens produced by the tokenizer are then placed in the new string array cmdarray, in the same order.

The two spaces are lost at this point and become one space when the command string is reassembled by the OS.

Jim Garrison
  • 85,615
  • 20
  • 155
  • 190