Create new files at the same time

To create a new unique file name, I use the following code:

File file = new File(name); synchronized (sync) { int cnt = 0; while (file.exists()) { file = new File(name + " (" + (cnt++) + ")"); } file.createNewFile(); } 

Then I use the file and delete it. When I do this in a multi-threaded situation, sometimes I get exceptions from file.createNewFile() :

 java.io.IOException: Access is denied at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(File.java:1012) 

The following code reproduces the problem (most of the time):

 final int runs = 1000; final int threads = 5; final String name = "c:\\temp\\files\\file"; final byte[] bytes = getSomeBytes(); final Object sync = new Object(); ExecutorService exec = Executors.newFixedThreadPool(threads); for (int thread = 0; thread < threads; thread++) { final String id = "Runnable " + thread; exec.execute(new Runnable() { public void run() { for (int i = 0; i < runs; i++) { try { File file = new File(name); synchronized (sync) { int cnt = 0; while (file.exists()) { file = new File(name + " (" + (cnt++) + ")"); } file.createNewFile(); } Files.write(file.toPath(), bytes); file.delete(); } catch (Exception ex) { System.err.println(id + ": exception after " + i + " runs: " + ex.getMessage()); ex.printStackTrace(); return; } } System.out.println(id + " finished fine"); } }); } exec.shutdown(); while (!exec.awaitTermination(1, TimeUnit.SECONDS)); 

The getSomeBytes() method simply generates the number of bytes, the actual content is not important:

 byte[] getSomeBytes() throws UnsupportedEncodingException, IOException { byte[] alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWYZ1234567890\r\n" .getBytes("UTF-8"); try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { for (int i = 0; i < 100000; i++) { baos.write(alphabet); } baos.flush(); return baos.toByteArray(); } } 

When I execute this code, it sometimes goes well, but most of the time it throws some exceptions, like the following below:

 Runnable 1: exception after 235 runs: Access is denied java.io.IOException: Access is denied at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(File.java:1012) at test.CreateFilesTest$1.run(CreateFilesTest.java:36) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Runnable 4: exception after 316 runs: Access is denied java.io.IOException: Access is denied at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(File.java:1012) at test.CreateFilesTest$1.run(CreateFilesTest.java:36) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Runnable 2: exception after 327 runs: Access is denied java.io.IOException: Access is denied at java.io.WinNTFileSystem.createFileExclusively(Native Method) at java.io.File.createNewFile(File.java:1012) at test.CreateFilesTest$1.run(CreateFilesTest.java:36) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745) Runnable 3 finished fine Runnable 0 finished fine 

Any ideas? I tested on a Windows 8 machine with java 1.7.0_45 and 1.8.0_31, both results.

Not sure if the problem is the same as in this question , but it could be. Using multiple threads in the same process seems to be part of the problem in my opinion, but I cannot be sure of it, however it reproduces faster.

+5
source share
2 answers

It appears that on Windows, createNewFile may crash accidentally if a file of the same name was simply deleted even in a single-threaded application. See this question for more details. To fix the problem, you can try to ignore the IOException from createNewFile and continue. Something like that:

 synchronized (sync) { int cnt = 0; while (true) { try { if(file.createNewFile()) break; } catch (IOException e) { // continue; } file = new File(name + " (" + (cnt++) + ")"); } } 

Note that you do not need to check the call to file.exists() , as createNewFile() conveniently returns whether it created the file successfully.

Please note that if you manage all temporary files created and do not care about the exact file name, there is usually no need to block. You can simply use the global AtomicLong to get the next file name or add a stream identifier to the file name.

+5
source

Your loop is not fault tolerant. There is a problem with the temporary window. It should be something like this:

 while (!file.createNewFile()) { file = new File(name + " (" + (cnt++) + ")"); } 
0
source

All Articles