Prüfen ob Datei noch geöffnet ist

Bluedaishi

Bekanntes Mitglied
Hallo zusammen ,
ich habe ein externes Programm das mir eine Datei anlegt diese möchte ich mit meinem Parser durchlaufen . Mein Problem ist das ich nicht weiß wie lange das extreme Programm dafür braucht um alle Daten in die Datei zuschreiben . Meine Idee war nun über eine while(True) Schleife alle 2 Sekunden abzufragen ob diese noch geöffnet ist leider funktioniert das nicht .
 
Ich bin mir nicht sicher, ob man das wirklich über die File-API von Java hinbekommt, rauszufinden ob ein anderes Programm die Datei noch schreibt.

Wird das externe Programm von Java aus gestartet? Dann könnte man das ggf. auswerten ob es fertig ist.

Ansonsten sehe ich die Möglichkeit, alle 2 Sekunden zu prüfen ob sich die Dateigröße geändert hat. Wenn nein - vermutlich fertig.
 
Hat bei mir nicht wirklich geklappt. Ich habe dann als Workaorund die Datei einfach umbenannt. Wenn das geklappt hat ist sie wirklich geschlossen gewesen. Kann aber auch sein, dass ich beim Lock irgendwas falsch gemacht habe damals.

Gruß

Claus
 
Generell muss man da aber auch auf das Betriebssystem / Dateisystem achten. Unter Linux wird ein Umbenennen und Löschen gut funktionieren, auch wenn die Datei geöffnet ist. Die Applikation schreibt dann fleißig weiter und bekommt davon auch nichts mit 🙂

Und das Vorgehen dürfte sein:
a) Erst ein RandomAccessFile erzeugen mit rw -> So die Datei geblockt wurde wird dies schon fehlschlagen vermute ich.
b) Dann kann man sich mit getChannel den FileChannel geben lassen.
c) Mit dem FileChannel kann man dann noch ein tryLock aufrufen. Wenn da null zurück gegeben wurde, dann wird die Datei noch woanders geöffnet sein. (Ich vermute, dass hier ein komplett exclusiver Lock angefordert wird. Wenn die Datei also von jemandem nur gelesen wird der die Datei aber nicht exclusiv haben wollte und auch weiteres Schreiben erlaubte, dann wird so eine Verbindung ein solchen Exclusiven Lock verhindern. Daher vermute ich, dass Du hier eigentlich nie rein laufen wirst ...

Das sind aber jetzt größtenteils Vermutungen - ich habe mir nicht angesehen, was da denn unter dem Strich lokal aufgerufen wird.
 
Also ich hab das mit der Datei Größe versucht klappt aber nicht
Java:
while(true){
   if(file.length() > 0.0){
      // datei von meinem Programm öffnen
       break;
    }else{
      // datei noch geöffnet
   }
}
 
Nein, so funktioniert das auch nicht.
Ich meinte, ob sich die Größe ändert, nicht ob es eine Größe von ungleich 0 hat.

Also so in der Art
Java:
long oldSize = 0;
while(true) {
  long size = file.length();
  if (size == oldSize) {
    break;
  }
  oldSize = size;
  Thread.sleep(2000);
}
 
Also das mit der Dateigröße ist keine wirklich gute Lösung. Je nachdem, die die Datei geschrieben wird, kann es durchaus etwas dauern, bis die Größe sich ändert. Hast Du es mit dem Ansatz probiert, den ich beschrieben habe? Das könnte dann in etwa so aussehen:
Java:
    public static boolean isLocked(String fileName) {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
             FileLock lock = randomAccessFile.getChannel().lock()) {
            return lock == null;
        } catch (IOException ex) {
            return true;
        }
    }

Edit: Bedingung umgedreht - muss lock == null sein und nicht lock != null!
 
Die Variante von JustNobody ist besser, meine ist eine Krücke, wenn die nicht greift, weil das FileSystem keine Möglichkeit bereitstellt um das zu prüfen.
 
Kleiner Tipp - Bei sowas immer in die API Doku schauen. Bei FileChannel.lock() handelt es sich um eine blocking Operation, die kehrt erst zurück, wenn ein Lock geholt wurde:

https://docs.oracle.com/javase/7/docs/api/java/nio/channels/FileChannel.html#lock() Verweist auf die lock Methode mit 3 Parametern und da steht:

An invocation of this method will block until the region can be locked, this channel is closed, or the invoking thread is interrupted, whichever comes first.
 
Alles klar super werd ich heute Abend testen vielen Dank euch allen ... wenn ich nicht weiter kommen sollte werde ich mich heute Abend noch mal melden
 
also entweder bin ich zu bl.... oder habe das nicht verstanden ich rufe isLocked(dateiName); auf und das programm macht gleich
mit den nächsten metoden weiter anstatt zu warten bis die datei zuende geschrieben ist
 
Java:
public static parser(){
isLocked(rootPathWin + "\\text.dat");
              
   dateiSplitt();
   parseDatei();
}


public static boolean isLocked(String fileName) {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
                FileLock lock = randomAccessFile.getChannel().lock()) {
            return lock == null;
        } catch (IOException ex) {
            return true;
        }
    }
 
Java:
boolean isFertig1 = isLocked(rootPathWin + "\\datei.dat");
                    System.out.println(isFertig1);
                    while (isFertig1 == true) {
                        dateiSplit();
                        parseDatei();
                        break;
                    }

es klappt aber leider nicht
 
habe es versucht in die datei zuschreiben wenn diese von dem externen programm angelegt etwas hinein zuschreiben aber schon beim öffnen sagt windows das die datei von einem anderen prozess geöffnet ist
 
Wie schon geschrieben: zu dem FileChannel wird er wohl nicht kommen sondern das RandomAccessFile wird nicht geöffnet werden können ... Eine Warteschleife könnte also sein, dass man while(isLocked(...)) Thread.sleep(1000); macht.

Nach der Schleife wäre dann die Abarbeitung....
 
Java:
while (tryWriteLock(rootPathWin + "\\datei.dat")) {
                        Thread.sleep(1000);
                    }
                    
                        dateiSplit();
                        parseDatei();

und die tryWriteLock

Java:
 public static boolean tryWriteLock(String fileName) {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
                FileLock lock = randomAccessFile.getChannel().lock()) {
            if (lock == null) {
                return false;
            } else {
                return true;
            }
        } catch (IOException e) {
            return false;
        }
    }

hab irgendwie ein Brett vor dem kopf ...... sorry
 
Ganz grundsätzliche: bei deinem Code hier, solltest du vielleicht noch ein bisschen Grundlagen angucken.


Zu dem Code: Nimm den Code von @JustNobody (änder daran nichts!), und bau die Schleife ein, die er grad eben genannt hat.

Irgendwo:
Java:
public static boolean isLocked(String fileName) {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
             FileLock lock = randomAccessFile.getChannel().lock()) {
            return lock == null;
        } catch (IOException ex) {
            return true;
        }
    }

Da, wo du warten willst, bis fertig ist:

Java:
while(isLocked(rootPathWin + "\\datei.dat")) Thread.sleep(1000);

dateiSplit();
parseDatei();
 
Deine Routine hat ja die Rückgabe umgedreht und True wird zurück gegeben, wenn die Datei nicht gesperrt ist.
Daher müsstest du bei deiner Methode die Bedingung in der while Schleife negieren, also !tryWriteLock(....) abfragen.
 
super jetzt funktioniert es Einwand frei 🙂 toll danke schön an alle die mir geholfen haben 🙂 und das noch um diese Uhrzeit
dieses forum ist wirklich das beste suppppppeeeeerrrrrrrrrr
 
Guten Morgen eine Frage noch zu diesem Thema muss ich nicht noch ein lock.release ausführen damit die Datei wieder benutzt werden kann
 
Hab es jetzt anders gelöst da scheinbar doch noch ein Zugriff besteht , lösche ich die Datei nach dem Durchlauf des parsers . Da das externe Programm die Datei sowieso wieder neu anlegt wenn sie nicht vorhanden ist
 
Also wenn du die Datei (unter Windows) löschen konntest, dann war da auch kein Lock drauf. Daher hätte man mal schauen müssen, was genau Du machst und was die exakte Fehlermeldung ist... Aber wenn Du jetzt eine Lösung für Dich hast, dann ist es natürlich auch ok.
 
Naja lieber wäre es mir ich müsste die Datei nicht löschen . Ich hab es genauso gemacht wie es vorher besprochen war wo ich geschrieben habe das es funktioniert🙂
 
Also der Lock sollte - wie von mihe7 schon geschrieben - bereits geschlossen worden sein, denn er ist ja im try with resources drin.

Aber: Wir gehen immer von dem Code aus, den wir hier sehen. Du müsstest uns Deinen Code schon zeigen, damit wir dazu etwas sagen können!
 
Java:
public static rufeDaten(){

                    buf.append("zugang=" + zugang + "\r\n");
                    buf.append("datei=DATEI.DAT" + "\r\n");
                    buf.append("+0000S01010101lgS  C" + "\r\n");
                    buf.append(">>>" + "\r\n");
                    String send = buf.toString();
                    out.write(send.getBytes());
                    out.flush();
                    out.close();
                    Thread.sleep(2000);

                    while (isLocked(rootPathWin + "\\Datei.dat")) {
                        Thread.sleep(1000);
                    }

                    dateiSplit();
                    parseDatei();

}

public static boolean isLocked(String fileName) {
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(fileName, "rw");
                FileLock lock = randomAccessFile.getChannel().lock()) {
            return lock == null;
        } catch (IOException ex) {
            return true;
        }
    }
 
Das mit dem Lock gibt die Datei wieder frei. Was machst Du in
Code:
                    dateiSplit();
                    parseDatei();
mit der Datei?
 
Java:
private void dateiSplit() throws FileNotFoundException, IOException {

        String line = "";
        String zul = "";
        int test = 0;

        String rootPath = rootPathWin;

        try {
            BufferedReader b = new BufferedReader(new InputStreamReader(new FileInputStream(rootPath + "\\fern.dat")));
            BufferedWriter br = null;
            while ((line = b.readLine()) != null) {
             
                if (line.startsWith("\021\033S")) {
                    test++;
                    File file = new File(rootPath + "\\" + test + ".fuell");
                    if (file.exists()) {
                        file.delete();
                    }
                    br = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(rootPath + "\\" + test + ".fuell")));
                    br.write(line + "\n");
                    while ((line = b.readLine()) != null) {
                        if ((!line.startsWith("ENDE    NL")) & (!line.startsWith("FIN NC NL")) & (!line.startsWith("\004\033"))) {
                            br.write(line + "\n");
                            br.flush();
                        } else {
                            br.write(line + "\n");
                            br.flush();
                            break;
                        }
                    }
                    br.flush();
                }

            }
            br.close();
            b.close();
        } catch (Exception ex) {
            System.out.println(ex);
        }

    }
 
Also was mir da direkt auffällt ist:
a) Du verwendest kein try with resources (was nicht per se falsch ist), aber das Schließen wird nicht gemacht, wenn eine Exception auftritt.
b) Du schließt nur den letzten BufferedWriter. Damit werden die geschriebenen Dateien etwas länger geöffnet bleiben.

Generell bietet es sich hier bei bei b und br an, try-with-resources zu nutzen.
 
ahh verstanden danke . meinst du das liegt daran das die datei.dat noch geöffnet ist obwohl ja der bufferedreader (b) unten geschlossen wird
 
Die Datei des Readers wird geschlossen und sollte nicht mehr offen sein (So keine Exception geworfen wurde - hast Du eine entsprechende Exception?)
Die Dateien des Writes (*.fuell) werden bis auf die letzte nicht geschlossen.
 
Java:
 while ((line = b.readLine()) != null) {
                        if ((!line.startsWith("ENDE    NL")) & (!line.startsWith("FIN NC NL")) & (!line.startsWith("\004\033"))) {
                            br.write(line + "\n");
                            br.flush();
                            br.close();
                        } else {
                            br.write(line + "\n");
                            br.flush();
                            break;
                        }
                    }
                    br.flush();

jetzt aber 🙂
 
Wieso schaust Du Dir nicht das try with resources an? Wenn eine Exception auftritt, wird kein close() mehr aufgerufen....
Dazu kommt noch, dass die Exception Behandlung nur ein einfaches println ist! Also gute Chancen, dass Du dies auch noch übersichst.

Java:
private void dateiSplit() throws FileNotFoundException, IOException {

        String line = "";
        String zul = "";
        int test = 0;

        String rootPath = rootPathWin;

        // Der hier war trivial, da ehh schon ein try vorhanden war!
        try (BufferedReader b = new BufferedReader(new InputStreamReader(new FileInputStream(rootPath + "\\fern.dat")))) {
            // Das schieben wir dann auch mal dahin, wo es hin gehört ..
            // BufferedWriter br = null;
            while ((line = b.readLine()) != null) {
            
                if (line.startsWith("\021\033S")) {
                    test++;
                    File file = new File(rootPath + "\\" + test + ".fuell");
                    if (file.exists()) {
                        file.delete();
                    }
                    // Hier kommt dann noch ein try dazu ...
                    try (BufferedWriter br = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(rootPath + "\\" + test + ".fuell")))) {
                      br.write(line + "\n");
                      while ((line = b.readLine()) != null) {
                         br.write(line + "\n"); // Das kommt ja immer, also gerne außerhalb der if Abfrage.
                         if ((!line.startsWith("ENDE    NL")) & (!line.startsWith("FIN NC NL")) & (!line.startsWith("\004\033"))) {
//                            br.write(line + "\n");
//                            br.flush();
                          } else {
//                            br.write(line + "\n");
//                            br.flush();
                            break;
                          }
                      }
                    }
                    br.flush();
                }

            }
            // Die fliegen raus!
//            br.close();
//            b.close();
        } catch (Exception ex) {
            System.out.println(ex);
        }

    }

Und die flush() Aufrufe müssten eigentlich auch gehen können. Beim Schließen kommt beim BufferedWriter meines Wissens auch vorab ein flush().

Und dann noch das if invertieren so dass man da nur noch ein if (...) break; hat und der Code ist deutlich kleiner und übersichtlicher geworden ...
 

Neue Themen


Zurück
Oben