public static Path getOutputPath(Path outputRoot, String initialRelativePath, HANDLE_EXISTING handleExisting, String suffix) throws IOException {

        String localSuffix = (suffix == null) ? "" : suffix;
        Path cand = FSUtil.resolveRelative(outputRoot, initialRelativePath + "." + localSuffix);
        if (Files.exists(cand)) {
            if (handleExisting.equals(HANDLE_EXISTING.OVERWRITE)) {
                return cand;
            } else if (handleExisting.equals(HANDLE_EXISTING.SKIP)) {
                return null;
            }
        }

        //if we're here, the output file exists, and
        //we must find a new name for it.

        //groups for "testfile(1).txt":
        //group(1) is "testfile"
        //group(2) is 1
        //group(3) is "txt"
        //Note: group(2) can be null
        int cnt = 0;
        String fNameBase = null;
        String fNameExt = "";
        //this doesn't include the addition of the localSuffix
        Path candOnly = FSUtil.resolveRelative(outputRoot, initialRelativePath);
        Matcher m = FILE_NAME_PATTERN.matcher(candOnly
                .getFileName()
                .toString());
        if (m.find()) {
            fNameBase = m.group(1);

            if (m.group(2) != null) {
                try {
                    cnt = Integer.parseInt(m.group(2));
                } catch (NumberFormatException e) {
                    //swallow
                }
            }
            if (m.group(3) != null) {
                fNameExt = m.group(3);
            }
        }

        Path outputParent = cand.getParent();
        while (fNameBase != null && Files.exists(cand) && ++cnt < 10000) {
            String candFileName = fNameBase + "(" + cnt + ")." + fNameExt + "" + localSuffix;
            cand = FSUtil.resolveRelative(outputParent, candFileName);
        }
        //reset count to 0 and try 20000 times
        cnt = 0;
        while (Files.exists(cand) && cnt++ < 20000) {
            UUID uid = UUID.randomUUID();
            cand = FSUtil.resolveRelative(outputParent, uid.toString() + fNameExt + "" + localSuffix);
        }

        if (Files.exists(cand)) {
            throw new IOException("Couldn't find candidate output file after trying " + "very, very hard");
        }
        return cand;
    }
Given an output root and an initial relative path,
return the output file according to the HANDLE_EXISTING strategy
<p/>
In the most basic use case, given a root directory "input",
a file's relative path "dir1/dir2/fileA.docx", and an output directory
"output", the output file would be "output/dir1/dir2/fileA.docx."
<p/>
If HANDLE_EXISTING is set to OVERWRITE, this will not check to see if the output already exists,
and the returned file could overwrite an existing file!!!
<p/>
If HANDLE_EXISTING is set to RENAME, this will try to increment a counter at the end of
the file name (fileA(2).docx) until there is a file name that doesn't exist.
<p/>
This will return null if handleExisting == HANDLE_EXISTING.SKIP and
the candidate file already exists.
<p/>
This will throw an IOException if HANDLE_EXISTING is set to
RENAME, and a candidate cannot output file cannot be found
after trying to increment the file count (e.g. fileA(2).docx) 10000 times
and then after trying 20,000 UUIDs.

@param outputRoot          root directory into which to put the path
@param initialRelativePath relative path including file ("somedir/subdir1/file.doc")
@param handleExisting      policy for what to do if the output path already exists
@param suffix              suffix to add to the output path
@return can return null
@throws IOException
tika-batch/src/main/java/org/apache/tika/batch/fs/FSUtil.java