2013-03-20 11 views
6

Ich folgte dem Tutorial Watching a Directory für Änderungen Java7 nio2, um den gesamten Inhalt eines Verzeichnisses mit dem Codebeispiel WatchDir.java rekursiv zu überwachen.Java 7 WatchService - Der Prozess kann nicht auf die Datei zugreifen, weil sie von einem anderen Prozess verwendet wird

Der Code sieht wie folgt aus:

// Get list of events for the watch key. 
for (WatchEvent<?> event : key.pollEvents()) { 
// This key is registered only for ENTRY_CREATE events, but an OVERFLOW event 
// can occur regardless if events are lost or discarded. 
if (event.kind() == OVERFLOW) { 
    continue; 
} 

// Context for directory entry event is the file name of entry. 
@SuppressWarnings("unchecked") 
WatchEvent<Path> ev = (WatchEvent<Path>)event; 
Path fileName = ev.context(); 
Path fullPath = dir.resolve(fileName); 

try { 
    // Print out event. 
    System.out.print("Processing file: " + fileName); 

    processed = fileProcessor.processFile(fullPath); 

    System.out.println("Processed = " + processed); 

    if (processed) { 
     // Print out event. 
     System.out.println(" - Done!"); 
    } 
} 
catch (FileNotFoundException e) { 
    System.err.println("Error message: " + e.getMessage()); 
} 
catch (IOException e) { 
    System.err.println("Error processing file: " + fileName.toString()); 
    System.err.println("Error message: " + e.getMessage()); 
} 

Ok, so dass das Problem (wo ich bin sicher, etwas Dummes zu tun) ist hier:

processed = fileProcessor.processFile(fullPath); 

Und was es tut, ist so etwas wie dieses:

public synchronized boolean processFile(Path fullPath) throws IOException { 
String line; 
String[] tokens; 
String fileName = fullPath.getFileName().toString(); 
String fullPathFileName = fullPath.toString(); 

// Create the file. 
File sourceFile = new File(fullPath.toString()); 

// If the file does not exist, print out an error message and return. 
if (sourceFile.exists() == false) { 
    System.err.println("ERROR: " + fullPathFileName + ": No such file"); 
    return false; 
} 

// Check file extension. 
if (!getFileExtension(fullPathFileName).equalsIgnoreCase("dat")) { 
    System.out.println(" - Ignored."); 
    return false; 
} 

// Process source file. 
try (BufferedReader bReader = new BufferedReader(new FileReader(sourceFile))) { 
    int type; 

    // Process each line of the file. 
    while (bReader.ready()) { 

     // Get a single line. 
     line = bReader.readLine(); 

     // Get line tokens. 
     tokens = line.split(delimiter); 

     // Get type. 
     type = Integer.parseInt(tokens[0]); 

     switch (type) { 
     // Type 1 = Salesman. 
     case 1: 
      -> Call static method to process tokes. 
      break; 
     // Type 2 = Customer. 
     case 2: 
      -> Call static method to process tokes. 
      break; 
     // Type 3 = Sales. 
     case 3: 
      -> Call static method to process tokes. 
      break; 
     // Other types are unknown! 
     default: 
      System.err.println("Unknown type: " + type); 
      break; 
     } 
    } 

    PrintStream ps = null; 
    try { 

     // Write output file. 
     // Doesn't matter. 

    } 
    finally {    
     if (ps != null) { 
      ps.close(); 
     } 
    } 
    return true; 
} 
} 

Das erste Mal, wenn ich ein Ereignis behandle, funktioniert alles gut! Auch wenn mehr als 1 Datei zu verarbeiten ist. Aber in den aufeinander folgenden Zeiten, ich diese Fehlermeldung:

Der Prozess kann nicht auf die Datei zugreifen kann, weil sie von einem anderen Prozess verwendet wird

Was mache ich hier falsch? Was kann ich tun, um die aufeinanderfolgenden Dateien mit Erfolg zu verarbeiten?

Zwei wichtige Hinweise, die ich vergessen zu erwähnen:

  1. Ich verwende Windows 7.
  2. Wenn ich die Anwendung im Debug-Modus laufen, es funktioniert.

EDIT: Wenn ich einen Schlaf hinzufügen, bevor ich versuche, die Datei zu verwenden, funktioniert es:

Thread.sleep(500); 

// Process source file. 
try (BufferedReader bReader = new BufferedReader(new FileReader(sourceFile))) { 

So ist es möglich, Windows zu sein, die nicht auf die Dateien in der Zeit Entriegeln? Wie kann ich das (richtig) beheben?

Antwort

14

Ok, ich habe eine Lösung gefunden. Ich weiß nicht, ob das der beste Weg ist, aber es funktioniert. Leider geben file.canRead() und file.canWrite() beide true zurück, auch wenn die Datei immer noch von Windows gesperrt ist. Also entdeckte ich, dass ich, wenn ich versuche, sie mit dem gleichen Namen "umzubenennen", weiß, ob Windows daran arbeitet oder nicht. Also das ist was ich getan habe:

while(!sourceFile.renameTo(sourceFile)) { 
     // Cannot read from file, windows still working on it. 
     Thread.sleep(10); 
    } 
+0

es geht um :) –

+1

Nice Trick! Es hat mir geholfen! –

1

Ich hatte das ähnliche Problem. Aber meine Datei wird beim Kopieren nicht gesperrt. Wenn ich versucht hätte, es direkt nach dem Ereignis zu lesen, dass es leer war.

Ich denke in Ihrem Fall gibt es keine Notwendigkeit, Tricks und Sie können einfach Fehler behandeln und wenn Sie Fehler bekommen, dann können Sie den Schlaf ausführen und versuchen Sie es erneut danach. Aber für mich ist es nicht richtig für mich. Ich bekomme keinen Fehler. Also habe ich deine Lösung versucht und ich habe verstanden, dass das für mich auch nicht akzeptabel ist, weil ich keine Rechte habe, außer zu lesen. Also kann ich meinen 'Trick' vorschlagen. Ich verwende Klasse java.io.RandomAccessFile:

List<String> lines = null; 

while(true){ 
    try(RandomAccessFile raf = new RandomAccessFile(fileFullPath.toFile() , "r")){ 
     lines = Files.readAllLines(fileFullPath , Charset.forName(ENCODING)); 
     break; 
    }catch(FileNotFoundException ex){ 
     LOG.warn("File isn't yet completed: {}",ex.getMessage()); 
     LOG.info("Waiting {} for next attempt to read it" , SLEEP_INTERVAL_READING); 
     try { 
      Thread.sleep(SLEEP_INTERVAL_READING); 
     } catch (InterruptedException e) { 
      LOG.error("Waiting was interrupted",e); 
     } 
    }catch(Exception ex){ 
     LOG.error("Error in reading file ",ex); 
     clear(); 
     return false; 
    } 
} 
0

Wenn Ereignis vom Typ ENTRY_MODIFY bitte den aktuellen Thread für einige Sekunden schlafen lassen. Ich kann nicht genau sagen, warum das passiert, aber einige Zeit mehrere ENTRY_MODIFY Ereignis in meinen Protokollen drucken. Abhängig von Ihrer Dateigröße stellen Sie bitte die Ruhezeit ein.

if(kind == StandardWatchEventKinds.ENTRY_MODIFY){ 
try { 
    Thread.sleep(1000); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} 
//toDo - something 
} 
Verwandte Themen