Frage

I haben zwei unabhängige Fäden F1 und F2 (um genau zu sein, zwei Instanzen von java.util.concurrent.FutureTask), die parallel ausgeführt werden.

F1 tun einige Verarbeitung, und dann das Ergebnis in einer XML-Datei kopieren. Dann wiederholt er diese Schritte, bis es nichts zu tun hat (viele XML-Dateien erstellt). F2 sieht in dem F1-Ausgabeverzeichnis und eine Datei nehmen, analysieren sie und führen Sie einige Verarbeitung auf sich.

Das funktioniert ganz recht gut, außer dass manchmal, F2 wird abgeschnitten XML-Daten aus der Datei. Damit meine ich, dass eine unvollständige XML, wo einig XML-Knoten nicht vorhanden ist. Das Problem ist, dass es nicht immer reproduzierbar ist, und die Dateien, die abgeschnitten werden, sind nicht immer gleich. Aus diesem Grund denke ich, dass, während F1 eine Datei auf der Festplatte schreibt, F2 versucht, die gleiche Datei zu lesen. Deshalb habe ich manchmal diese Art von Fehler.

Meine Frage : Ich frage mich, ob es einen Mechanismus ist, die Sperren (auch zum Lesen) auf die Datei F1 zur Zeit das Schreiben ist, bis er vollständig beendet hat es auf die Platte zu schreiben, so F2 wird nicht der Lage sein, es zu lesen, bis die Datei freigeschaltet wird. Oder eine andere Möglichkeit, mein Problem zu lösen, wird willkommen sein!

F1 ist das Schreiben der Datei auf diese Weise:

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 liest die Datei auf diese Weise:

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);
}
War es hilfreich?

Lösung

Da Sie bereits sind Filterung für .xml Dateien in F2, haben F1 Ausgabe in eine .temp Datei, benennen Sie es als letzten Schritt .xml. Auf diese Weise F2 wird die Datei F1 ignorieren macht, bis F1 vollständig mit ihr geschehen ist.

Andere Tipps

Haben Sie an der sah java.nio.channels.FileLock API?

Eine einfachere Lösung kann gut sein, zu einem anderen Dateinamen zu schreiben (zB foo.tmp) und dann umbenennen (zB foo.xml), wenn es fertig ist - die Umbenennungs ist atomar auf den meisten Betriebssystemen (innerhalb eines Verzeichnisses), so, wenn der andere Prozess die XML-Datei sieht es sollte vollständig sein. Dies ist wahrscheinlich viel einfacher zu sein als zu verriegeln.

Benutze das Stichwort synchronisiert auf einer gemeinsamen Objekt, ein File-Objekt auf die Datei verweist wäre das beste in diesem Fall:

 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
 }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top