2012-12-22 48 views
3

我想等到其他程序發佈鎖定特定文件,然後我想繼續打開解鎖的文件。如何等待並鎖定文件

我遇到了很多的解決方案,但沒有一個是有用的,這裏是我的代碼 -

File file = new File("c:\\somelockedfile.txt"); 
    FileChannel channel = null; 
    try{ 
     channel = new RandomAccessFile(file, "rw").getChannel(); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 
    try { 
     // Get an exclusive lock on the whole file 
     FileLock lock = channel.lock(); 
     try { 
      doWithLockedFile(file); 
     } finally { 
      lock.release(); 
     } 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } finally { 
     try{ 
      channel.close(); 
     }catch(Exception e){ 
      e.printStackTrace(); 
     } 
    } 

我知道當我將運行這段代碼,文件將通過其他的Windows進程被鎖定,所以我想等待其他進程釋放鎖定,然後我將繼續解鎖文件。如果我嘗試打開鎖定的文件,我將得到FileNotFoundException,如「(The process cannot access the file because it is being used by another process)」。

在上面的代碼,我不能等待獲得鎖,因爲同樣的異常將線拋出「channel = new RandomAccessFile(file, "rw").getChannel();

請幫我在這,基本上我想獲得通知其他進程的文件公佈鎖定,直到那個時候,我想等()。

+2

你爲什麼不只是使用'while'循環,直到你獲得信道保持和'線程。睡眠(1000)'每次嘗試之間?當然,嘗試次數有限。 – fge

+0

謝謝fge,我可以做到這一點,但是爲什麼FileLock在Java中存在?如果我們無法在鎖定的文件上創建頻道,我不明白如何等待並鎖定頻道的文件?我猜channel.lock()只是爲了這個目的。 – UDPLover

+0

請參閱http://stackoverflow.com/questions/4025721/java-file-locking它可能有幫助 – home

回答

0

我得到它的一些睡眠和排隊等待和獲取鎖的觀察員收到的文件名。

解決方案:

package dirwatch; 

import java.nio.file.*; 
import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; 
import static java.nio.file.StandardWatchEventKinds.OVERFLOW; 
import static java.nio.file.LinkOption.*; 
import java.nio.file.attribute.*; 
import java.io.*; 
import java.util.*; 
import java.util.concurrent.ArrayBlockingQueue; 
import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.TimeUnit; 

public class WatchDir { 
    private final WatchService watcher; 
    private final Map<WatchKey,Path> keys; 
    private final boolean recursive; 
    private boolean trace = false; 

    private BlockingQueue<String> fileProcessingQueue; 

    //******* processedFileQueue **** will be used by other threads to retrive unlocked files.. so I have 
    // kept as public final 
    public final BlockingQueue<String> processedFileQueue; 
    private volatile boolean closeProcessingThread; 
    private volatile boolean closeWatcherThread; 


    private void processFiles(){ 
     System.out.println("DirWatchProcessingThread Started"); 
     String fileName; 
     outerLoop: while(!closeProcessingThread || !fileProcessingQueue.isEmpty()){ 
      try{ 
       fileName = fileProcessingQueue.poll(1000, TimeUnit.MILLISECONDS); 
      }catch(InterruptedException ie){ 
       fileName = null; 
      } 

      if(fileName == null || fileName.equals("")){ 
       continue outerLoop; 
      } 

      long startTime = System.currentTimeMillis(); 
      innerLoop: while(true){ 
       FileInputStream fis = null; 
       File file = new File(fileName); 
       try{ 
        fis = new FileInputStream(fileName); 
        break innerLoop; 
       }catch(FileNotFoundException fnfe){ 
        if(!file.exists() || file.isDirectory()){ 
         System.out.println("File: '"+fileName+"has been deleted in file system or it is not file. Not processing this file."); 
         continue outerLoop; 
        } 
        try{ 
         Thread.sleep(WatchDirParameters.millisToPuaseForFileLock); 
        }catch(InterruptedException ie){ 
        } 
        if((System.currentTimeMillis() - startTime) > WatchDirParameters.millisToSwapFileForUnlocking){ 
         if(fileProcessingQueue.offer(fileName)){ 
          continue outerLoop; 
         }else{ 
          startTime = System.currentTimeMillis(); 
          continue innerLoop; 
         } 
        } 
       }finally{ 
        if(fis != null){ 
         try{ 
          fis.close(); 
         }catch(IOException ioe){ 
          ioe.printStackTrace(); 
         } 
        } 
       } 
      } 

      System.out.println("Queuing File: "+fileName); 
      processedLoop:while(true){ 
       try{ 
        if(processedFileQueue.offer(fileName, 1000, TimeUnit.MILLISECONDS)){ 
         break processedLoop; 
        } 
       }catch(InterruptedException ie){ 
        //ie.printStackTrace(); 
       } 
      } 
     } 
     closeWatcherThread = true; 
     closeProcessingThread = true; 
     System.out.println("DirWatchProcessingThread Exited"); 
    } 

    /** 
    * Process all events for keys queued to the watcher 
    */ 
    private void processEvents(){ 
     System.out.println("DirWatcherThread started."); 
     while(!closeWatcherThread) { 
      // wait for key to be signalled 
      WatchKey key; 
      try { 
       key = watcher.take(); 
      } catch (InterruptedException x) { 
       // if we are returning from these method, it means we no longer wants to watch directory 
       // we must close thread which may be waiting for file names in queue 
       continue; 
      }catch(ClosedWatchServiceException cwse){ 
       break; 
      } 

      Path dir = keys.get(key); 
      if (dir == null) { 
       System.err.println("WatchKey not recognized!!"); 
       continue; 
      } 

      try{ 
       for (WatchEvent<?> event: key.pollEvents()) { 
        WatchEvent.Kind kind = event.kind(); 

        if (kind == OVERFLOW) { 
         continue; 
        } 

        // Context for directory entry event is the file name of entry 
        WatchEvent<Path> ev = cast(event); 
        Path name = ev.context(); 
        Path child = dir.resolve(name); 
        if(kind.equals(ENTRY_CREATE)){ 
         // if directory is created, and watching recursively, then 
         // register it and its sub-directories 
         if (recursive) { 
          try { 
           if (Files.isDirectory(child, NOFOLLOW_LINKS)) { 
            registerAll(child); 
            continue; 
           } 
          } catch (IOException x) { 
           // ignore to keep sample readbale 
          } 
         } 
         while(true){ 
          if(fileProcessingQueue.remainingCapacity() < 2){ 
           // if only one last can be inserted then don't queue this we need 1 empty space in queue 
           // for swaping file names.. 
           // sleep for some time so processing thread may have made some rooms to queue in fileQueue 
           // this logic will not create any problems as only one this thread is inserting in queue 
           try{ 
            Thread.sleep(200); 
           }catch(InterruptedException ie){ 
           } 
           continue; 
          } 
          if(!fileProcessingQueue.offer(child.toString())){ 
           // couldn't queue this element by whatever reason.. we will try to enqueue again by continuing loop 
           continue; 
          }else{ 
           // file name has been queued in queue 
           break; 
          } 
         } 
        } 
       } 
       // reset key and remove from set if directory no longer accessible 
       boolean valid = key.reset(); 
       if (!valid) { 
        keys.remove(key); 

        // all directories are inaccessible 
        if (keys.isEmpty()) { 
         break; 
        } 
       } 
      }catch(ClosedWatchServiceException cwse){ 
       break; 
      } 

     } 
     closeProcessingThread = true; 
     closeWatcherThread = true; 
     System.out.println("DirWatcherThread exited."); 
    } 

    public void stopWatching(){ 
     try{ 
      watcher.close(); 
     }catch(IOException ioe){ 
     } 
     closeProcessingThread = true; 
     closeWatcherThread = true; 
    } 

    public static WatchDir watchDirectory(String dirName, boolean recursive) throws InvalidPathException, IOException, Exception{ 
     try{ 
      Path dir = Paths.get(dirName); 
      final WatchDir watchDir = new WatchDir(dir, recursive); 
      watchDir.closeProcessingThread = false; 
      watchDir.closeWatcherThread = false; 
      new Thread(new Runnable() { 
       public void run() { 
        watchDir.processFiles(); 
       } 
      }, "DirWatchProcessingThread").start(); 
      new Thread(new Runnable() { 
       public void run() { 
        watchDir.processEvents(); 
       } 
      }, "DirWatcherThread").start(); 
      return watchDir; 
     }catch(InvalidPathException ipe){ 
      throw ipe; 
     }catch(IOException ioe){ 
      throw ioe; 
     }catch(Exception e){ 
      throw e; 
     } 
    } 

    @SuppressWarnings("unchecked") 
    private static <T> WatchEvent<T> cast(WatchEvent<?> event) { 
     return (WatchEvent<T>)event; 
    } 

    /** 
    * Register the given directory with the WatchService 
    */ 
    private void register(Path dir) throws IOException { 
     //WatchKey key = dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); 
     WatchKey key = dir.register(watcher, ENTRY_CREATE); 
     if (trace) { 
      Path prev = keys.get(key); 
      if (prev == null) { 
       System.out.format("register: %s\n", dir); 
      } else { 
       if (!dir.equals(prev)) { 
        System.out.format("update: %s -> %s\n", prev, dir); 
       } 
      } 
     } 
     keys.put(key, dir); 
    } 

    /** 
    * Register the given directory, and all its sub-directories, with the 
    * WatchService. 
    */ 
    private void registerAll(final Path start) throws IOException { 
     // register directory and sub-directories 
     Files.walkFileTree(start, new SimpleFileVisitor<Path>() { 
      @Override 
      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException { 
       register(dir); 
       return FileVisitResult.CONTINUE; 
      } 
     }); 
    } 

    /** 
    * Creates a WatchService and registers the given directory 
    */ 
    private WatchDir(Path dir, boolean recursive) throws IOException { 
     fileProcessingQueue = new ArrayBlockingQueue<String>(WatchDirParameters.fileQueueSize, false); 
     processedFileQueue = new ArrayBlockingQueue<String>(WatchDirParameters.fileQueueSize, false); 
     this.watcher = FileSystems.getDefault().newWatchService(); 
     this.keys = new HashMap<WatchKey,Path>(); 
     this.recursive = recursive; 
     //CreateTxtFile.createFile(dir, 1); 
     if (recursive) { 
      System.out.format("Scanning %s ...\n", dir); 
      registerAll(dir); 
      System.out.println("Done."); 
     } else { 
      register(dir); 
     } 

     // enable trace after initial registration 
     this.trace = true; 
    } 
} 

配置類:

package dirwatch; 

public class WatchDirParameters { 
    public static final int millisToPuaseForFileLock = 200; 
    public static final int fileQueueSize = 500; 
    public static final int millisToSwapFileForUnlocking = 2000; 
} 
+0

如果你可以發佈你的工作解決方案來避免這種情況,那將是非常好的:http://xkcd.com/979/ –

+0

當然..,讓我粘貼在這裏.. – UDPLover

+0

@AlexanderWeinert我希望這可以幫助你。 :) – UDPLover

0

也許創建一個布爾值,將其設置爲true(鎖定)在catch部分,如果到達代碼的最後一個,這意味着它已解鎖並且一切正常。最後把整個事情放在一個do {} while(鎖定);祝你好運。

+0

感謝Jeroen,我得到了它的一些睡眠和排隊等待和獲取鎖的觀察員收到的文件名。 – UDPLover