-2

I'm writing a moving file program for my pc, to finish it I need to rename a moving file if in the target directory there is already a file named the same, how can i do that?

2 Answers2

0

One could use File.move and use CopyOptions. But it seems more elegant to check the existence of the target.

void move(Path source, Path target) throws IOException {
    int fileno = 0;
    while (Files.exist(target)) {
        target = ...
        ++fileno;
    }
    // Files.createDirectories(target.getParent());
    Files.move(source, target);
}

In java the convention is that the target is not a directory (the new parent).

Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

It's a programming language; you would program the behaviour you want. There is nothing 'baked in', if that's what you were thinking.

As with most things that could potentially interact with other threads or applications running simultaneously, you don't check-and-act - because other apps or threads could change the situation in between your 'check' and your 'act' - instead, you act-then-check: You just do the thing, and catch exceptions that indicate the thing cannot be done due to failing checks, and act accordingly. In other words, don't do something like:

while (file.exists()) file = incrementSomething();
writeTo(file);

That's check-then-act. Don't do that.

Instead you'd first just move it, and then catch the exception that indicates that it cannot be moved because the 'target' already exists and you did not specify that overwriting is acceptable.

It's your program, you decide what you want to do when this happens. Perhaps you want to append (1) to the file name and try again, then (2), and so on, all the way to (999) and once you get that far, just stop and crash. Or perhaps you want to roll up a random sequence of 6 characters and append that, which is a heck of a lot faster if this 'naming conflict' scenario is likely. That's the joy of programming: Anything's possible, you decide what you want and then you write it just like that.

Let's say you want the (1) thing. It would look something like:

public void move(Path sourceFile, Path targetDir) throws IOException {
  try {
    Files.move(sourceFile, targetDir.resolve(sourceFile.getFileName()));
  } catch (FileAlreadyExistsException e) {
    String baseName = sourceFile.getFileName().toString();
    int lastDot = baseName.lastIndexOf('.');
    String prefix = lastDot == -1 ? baseName : baseName.substring(0, lastDot);
    String suffix = lastDot == -1 ? "" : baseName.substring(lastDot);
    moveIncremental(sourceFile, targetDir, prefix, suffix, 1);
  }
}

private void moveIncremental(Path sourceFile, Path targetDir, String prefix, String suffix, int counter) throws IOException {

  Path target = targetDir.resolve(prefix + " (" + counter + ")" + suffix);
  try {
    Files.move(sourceFile, target);
  } catch (FileAlreadyExistsException e) {
    if (counter >= 999) throw e; // Give up after 1000 increments.
    moveIncremental(sourceFile, targetDir, prefix, suffix, counter + 1);
  }
}

This code first just tries to move it, and responds to the error of 'no can do; there is a file already there' and then breaks the file into a prefix and suffix, i.e. something.txt becomes prefix = "something" suffix = ".txt" and will then call a helper method that tries to move it to something (1).txt, all the way up to 999.

It's just one of many ways to do this - as I said, your choice.

rzwitserloot
  • 85,357
  • 5
  • 51
  • 72