Domanda

Ho due fili indipendenti F1 e F2 (per la precisione, due istanze di java.util.concurrent.FutureTask) che eseguono in parallelo.

F1 fare un po 'di elaborazione, e quindi copiare il risultato in un file XML. Poi, si ripete questa procedura fino a quando non ha nulla a che fare (vengono creati molti file XML). F2 cerca nella directory di output di F1, e prendere un file, analizzarlo, ed eseguire alcune elaborazioni su di esso.

Questo funziona abbastanza abbastanza bene, tranne che i dati XML a volte, F2 viene troncato dal file. Che intendo XML incompleto, dove qualche nodo XML non sono presenti. Il problema è che non è sempre riproducibile, ed i file che vengono troncati non sono sempre gli stessi. A causa di questo, penso che mentre F1 sta scrivendo un file sul disco, F2 sta cercando di leggere lo stesso file. Ecco perché a volte ho questo tipo di errore.

La mia domanda : Mi chiedo se c'è qualche meccanismo che blocca (anche per la lettura) il file F1 sta attualmente scrivendo finché non è completamente finito di scrivere sul disco, quindi F2 non lo farà essere in grado di leggere fino a quando il file viene sbloccato. O qualsiasi altro modo per risolvere il mio problema sarà il benvenuto!

F1 sta scrivendo il file in questo modo:

try {
    file = new File("some-file.xml");
    FileUtils.writeStringToFile(file, xmlDataAsString);
} catch (IOException ioe) {
    LOGGER.error("Error occurred while storing the XML in a file.", ioe);
}

F2 è la lettura del file in questo modo:

private File getNextFileToMap() {
    File path = getPath(); // Returns the directory where F1 stores the results...
    File[] files = path.listFiles(new FilenameFilter() {
        public boolean accept(File file, String name) {
            return name.toLowerCase().endsWith(".xml");
        }
    });
    if (files.length > 0) {
        return files[0];
    }
    return null;
}

// Somewhere in my main method of F2
...
f = getNextFileToMap();
Node xmlNode = null;
try {
    DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = factory.newDocumentBuilder();
    Document doc = builder.parse(f);
    if (doc != null) {
        xmlNode = doc.getDocumentElement();
    }
} catch (Exception e) {
    LOGGER.error("Error while getting the XML from the file " + f.getAbsolutePath(), e);
}
È stato utile?

Soluzione

Dal momento che si sta già filtrando per i file .xml in F2, hanno uscita di F1 in un file .temp, poi rinominarlo in .xml come passo finale. In questo modo, F2 ignorerà il file F1 sta facendo fino a quando F1 è completamente fatto con esso.

Altri suggerimenti

Avete guardato il java.nio.channels.FileLock API?

Una soluzione più semplice potrebbe essere di scrivere un nome diverso (ad esempio foo.tmp) e poi rinominarlo (ad esempio per foo.xml) quando è pronto - la ridenominazione è atomico sulla maggior parte dei sistemi operativi (all'interno di una directory), in modo che quando l'altro processo vede il file XML deve essere integro. Questo è probabile che sia molto più semplice di chiusura.

Usa la parola chiave sincronizzato su una comune oggetto, un oggetto File che punta al file sarebbe il migliore in questo caso:

 class MyFileFactory {
     private static HashMap<string,File> files = new HashMap<String,File>();
     public static File get(String name) {
         if (!files.keyExists(name)) {
              files.put(name, new File(name));
         }
         return files.get(name);
     }
 }

 // Another class
 synchronized(File f = MyFileFactory::get("some-file.xml")) {
      // read or write here
 }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top