0

I have simple class that is connected to the folder and I want to delete all regular files that are created, but when I read the file with same name (the same file is inserted into folder more than once or twice), I'm getting error

Exception in thread "main" java.lang.RuntimeException: java.nio.file.FileSystemException: c:\Temp\reader\msg.xml: The process cannot access the file because it is being used by another process.

    at com.project.test.Reader.lambda$0(Reader.java:38)
    at com.project.test.Reader$$Lambda$1/1418481495.accept(Unknown Source)
    at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1374)
    at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:580)
    at com.project.test.Reader.main(Reader.java:28)
Caused by: java.nio.file.FileSystemException: c:\Temp\reader\msg.xml: The process cannot access the file because it is being used by another process.

    at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:86)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
    at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
    at sun.nio.fs.WindowsFileSystemProvider.implDelete(WindowsFileSystemProvider.java:269)
    at sun.nio.fs.AbstractFileSystemProvider.delete(AbstractFileSystemProvider.java:103)
    at java.nio.file.Files.delete(Files.java:1126)
    at com.project.test.Reader.lambda$0(Reader.java:35)
    ... 4 more

Here is my reader class:

package com.project.test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardWatchEventKinds;
import java.nio.file.WatchEvent;
import java.nio.file.WatchKey;
import java.nio.file.WatchService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Stream;

public class Reader {

    public static void main(String[] args) {
        Path path = Paths.get("c:\\Temp\\reader\\");
        WatchService watchService;

        try {
            watchService = path.getFileSystem().newWatchService();
            path.register(watchService, StandardWatchEventKinds.ENTRY_CREATE);
            WatchKey watchKey = null;
            while (true) {
                watchKey = watchService.poll(5, TimeUnit.SECONDS);
                if (watchKey != null) {
                    try(Stream<WatchEvent<?>> events = watchKey.pollEvents().stream()) {
                        events.forEach(event -> {
                            if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) {
                                @SuppressWarnings("unchecked")
                                Path name = ((WatchEvent<Path>) event).context();
                                Path file = path.resolve(name);
                                try {
                                    if (Files.isRegularFile(file)) {
                                        Files.delete(file);
                                    }
                                } catch (Exception e) {
                                    throw new RuntimeException(e);
                                }
                            }
                        });
                    }
                    watchKey.reset();
                }
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}

Don't you know what is incorrect? I expect that should missed some "closing" on the file, but Path is only target on the file and shouldn't be closed, should be? Thanks for all tips.

user1604064
  • 809
  • 1
  • 9
  • 29
  • The files you are trying to delete, are they open somewhere else? – Prajjwal Srivastav May 19 '17 at 08:08
  • No they are not. I am just copy this file to the folder and it is deleted, but when I do the same again (copy the same file to the folder) it throws the exception. So I don't understand why the first deletion is successful, but the second one or the third one is not :/ – user1604064 May 19 '17 at 08:11
  • try sending different file to the folder, instead of same file – Prajjwal Srivastav May 19 '17 at 08:22
  • Yes it is working, but I need to delete files with same name and avoid to the mentioned error above – user1604064 May 19 '17 at 08:38
  • What about the creator? Is it so surprising that sometimes the creator didn’t close the file yet, if you try to delete it immediately after learning about its creation? – Holger May 19 '17 at 08:55
  • 1
    Hi Holger it seems that you're right. I try to debug it. After file has been deleted I wait on the breakpoint, put the same file to the folder and continue after few seconds and it is working :/ When I'm doing it without break point it is still failing. I tested it on Linux and there it is working, so it seems like a Windows issue :/ – user1604064 May 19 '17 at 10:39

1 Answers1

0

If you read the javadoc for the WatchService it says that the implementation is operating system dependent, ie. for some operating systems there might more than one event generated when a file is added to a folder:

For example, when a file in a watched directory is modified then it may result in a single ENTRY_MODIFY event in some implementations but several events in other implementations.

My hunch is this is what is happening in your case too.

Here are some similar discussions:

Java 7 WatchService - Ignoring multiple occurrences of the same event

Java NIO watch Service created both 'ENTRY_CREATE' and 'ENTRY_MODIFY' when a new File is added to the watch folder

What I would do to make it work is store the path of the file I am about to delete in a concurrent Set and only try to delete if the current path is not already in that Set.

Community
  • 1
  • 1
wi2ard
  • 1,471
  • 13
  • 24
  • I don't think so that concurrent set will solve this issue. Let's assume that I have to keep only folders in the root folder. So when someone copy file "msg.xml" into root folder, I will delete, but when someone copy again file "msg.xml" into root folder, I need to delete this file again and not to check if it has been deleted in a past – user1604064 May 19 '17 at 08:37
  • Well, of course, you should remove the file path from the set after you delete the file. If you mean in your comment that there is a risk to have a race condition (ie. after file deletion and before the path is removed from the set a new file with the same name is added to the folder generating another event) I don't see that happening because the events in your stream are not coming in "real-time", they are just a snap-shot you take every 5 seconds. I will add a code snippet when I get some free time. – wi2ard May 19 '17 at 11:21