10

I'm trying to implement the following operation in Java and am not sure how:

/*
 * write data (Data is defined in my package)
 * to a file only if it does not exist, return success
 */
boolean writeData(File f, Data d)
{
    FileOutputStream fos = null;
    try 
    {
        fos = atomicCreateFile(f);
        if (fos != null)
        {
            /* write data here */
            return true;
        }
        else
        {
            return false;
        }
    }
    finally
    {
        fos.close();  // needs to be wrapped in an exception block
    }
}

Is there a function that exists already that I can use for atomicCreateFile()?

edit: Uh oh, I'm not sure that File.createNewFile() is sufficient for my needs. What if I call f.createNewFile() and then between the time that it returns and I open the file for writing, someone else has deleted the file? Is there a way I can both create the file and open it for writing + lock it, all in one fell swoop? Do I need to worry about this?

Jason S
  • 184,598
  • 164
  • 608
  • 970

5 Answers5

20

File.createNewFile() only creates a file if one doesn't already exist.

EDIT: Based on your new description of wanting to lock the file after it's created you can use the java.nio.channels.FileLock object to lock the file. There isn't a one line create and lock though like you are hoping. Also, see this SO question.

Community
  • 1
  • 1
Taylor Leese
  • 51,004
  • 28
  • 112
  • 141
  • doh! how did I miss that? :/ thanks. My mind's been in C++ land. – Jason S Oct 12 '09 at 18:33
  • ok, thanks. Well it sounds like I have to think carefully about exceptional conditions. (e.g. if the createNewFile() succeeds but opening a file channel and getting a file lock fails) – Jason S Oct 12 '09 at 18:53
8

File.createNewFile()

Atomically creates a new, empty file named by this abstract pathname if and only if a file with this name does not yet exist. The check for the existence of the file and the creation of the file if it does not exist are a single operation that is atomic with respect to all other filesystem activities that might affect the file.

EDIT

Jason, as for your concern, if you keep reading the link we sent you there is a NOTE about that.

Note: this method should not be used for file-locking, as the resulting protocol cannot be made to work reliably. The FileLock facility should be used instead.

I think you should really read that part too:

alt

Undo
  • 25,519
  • 37
  • 106
  • 129
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • Thanks, I did read the note, that's what triggered the Uh oh. – Jason S Oct 12 '09 at 19:19
  • (Unfortunately there doesn't seem to be a repository of Java I/O paradigms, aside from manually exploring the platform javadocs, that says these are all the tools you have available... File and FileLock are in completely different packages, sometimes you use FileChannel, sometimes you use FileOutputStream... makes my head spin sometimes.) – Jason S Oct 12 '09 at 19:21
  • I found that one too, but I'm not using the file as a lock, I just want to be 100% sure that if I write to the file I'm the first one doing so, and no one else is touching it while I'm writing to it. – Jason S Oct 12 '09 at 21:38
2

Java 7 version with Files#createFile:

Path out;

try {
    out = Files.createFile(Paths.get("my-file.txt"));
} catch (FileAlreadyExistsException faee) {
    out = Paths.get("my-file.txt");
}
Stephan
  • 41,764
  • 65
  • 238
  • 329
-1

Why can't you test using File#exists?

Geo
  • 93,257
  • 117
  • 344
  • 520
  • 6
    because between the time you test using File.exists(), and you go to create a file if it doesn't exist, someone else might have created the file first. – Jason S Oct 12 '09 at 18:34
  • 5
    Because between the time `exists()` returns false and he constructs the `FileOutputStream` some other process could jump in and create the file. A classical race condition. – Joachim Sauer Oct 12 '09 at 18:34
  • 19
    (the same way I slipped in that comment just ahead of Joachim. :-) – Jason S Oct 12 '09 at 18:35
  • 3
    Excellent demonstration, indeed ;-) – Joachim Sauer Oct 12 '09 at 18:50
-2
//myFile should only be created using this method to ensure thread safety
public synchronized File getMyFile(){
  File file = new File("path/to/myfile.ext");
  if(!file.exists()){
     file.getParentFile().mkdirs();
     file.createNewFile();
  }
  return file;
}  
cosbor11
  • 14,709
  • 10
  • 54
  • 69
  • I changed the parameter to the File constructor to an actual string in case that is why it was failing. – cosbor11 Mar 09 '15 at 06:40
  • When the system is creating a file it will have a handle aka "lock" on it. – cosbor11 Mar 09 '15 at 06:41
  • When you write to the file it should also get a handle on the File object so no other thread can access it or delete it.You could write a JUnit test to confirm this. If you run into any problems you could run your operations in a synconized(){} block. – cosbor11 Mar 09 '15 at 06:43
  • Read [Geo's answer](http://stackoverflow.com/a/1556146/44330) and the associated comments. – Jason S Mar 09 '15 at 13:42
  • This file is a singleton then? I would make the method syncronized in this case that way only one thread can access it at a time. – cosbor11 Mar 09 '15 at 23:01
  • I'd write out another code sample in a separate answer, but i'm afraid you would dock my reputation points again - so I think I will just stay out of this post since the requirements are not very clearly defined. – cosbor11 Mar 09 '15 at 23:05