# Prüfen ob Datei noch geöffnet ist



## Bluedaishi (3. Dez 2019)

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 .


----------



## LimDul (3. Dez 2019)

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.


----------



## kneitzel (3. Dez 2019)

Was du probieren kannst ist die lock / tryLock vom FileChannel (java.nio package):
https://dzone.com/articles/locking-files-in-java

Wenn Du den Lock bekommen kannst, dann sollte die Datei nicht mehr geöffnet sein.


----------



## Bluedaishi (3. Dez 2019)

Nein dies ist leider kein Programm das aus Java heraus gestartet wird


----------



## Bluedaishi (3. Dez 2019)

Das heist wenn lock == null ist die Datei geöffnet


----------



## Thallius (3. Dez 2019)

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


----------



## kneitzel (3. Dez 2019)

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.


----------



## Bluedaishi (3. Dez 2019)

Also ich hab das mit der Datei Größe versucht klappt aber nicht

```
while(true){
   if(file.length() > 0.0){
      // datei von meinem Programm öffnen
       break;
    }else{
      // datei noch geöffnet
   }
}
```


----------



## Bluedaishi (3. Dez 2019)

Oder haut das wegen dem while(True) nicht hin


----------



## Bluedaishi (3. Dez 2019)

Die Schleife muss ja solange laufen bis die Datei fertig geschrieben ist


----------



## LimDul (3. Dez 2019)

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

```
long oldSize = 0;
while(true) {
  long size = file.length();
  if (size == oldSize) {
    break;
  }
  oldSize = size;
  Thread.sleep(2000);
}
```


----------



## kneitzel (3. Dez 2019)

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:

```
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!


----------



## LimDul (3. Dez 2019)

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.


----------



## Bluedaishi (3. Dez 2019)

Ja nur das ganze muss ja über eine while Schleife laufen da ich nicht weiß wann die Datei fertig geschrieben ist


----------



## Bluedaishi (3. Dez 2019)

Das wäre dann so while (true) islocked 
????


----------



## LimDul (3. Dez 2019)

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.


----------



## Bluedaishi (3. Dez 2019)

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


----------



## Bluedaishi (3. Dez 2019)

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


----------



## Bluedaishi (3. Dez 2019)

```
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;
        }
    }
```


----------



## mrBrown (3. Dez 2019)

isLocked gibt dir was zurück, das solltest du auch nutzen


----------



## Bluedaishi (3. Dez 2019)

ich kriege es nicht hin :-(


----------



## Bluedaishi (3. Dez 2019)

```
boolean isFertig1 = isLocked(rootPathWin + "\\datei.dat");
                    System.out.println(isFertig1);
                    while (isFertig1 == true) {
                        dateiSplit();
                        parseDatei();
                        break;
                    }
```

es klappt aber leider nicht


----------



## Bluedaishi (3. Dez 2019)

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


----------



## kneitzel (3. Dez 2019)

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....


----------



## Bluedaishi (3. Dez 2019)

hab ich versucht es wird die while schleife gestartet und gleich danach die beiden methoden aufgerufen :-(


----------



## Bluedaishi (3. Dez 2019)

```
while (tryWriteLock(rootPathWin + "\\datei.dat")) {
                        Thread.sleep(1000);
                    }
                    
                        dateiSplit();
                        parseDatei();
```

und die tryWriteLock


```
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


----------



## mrBrown (3. Dez 2019)

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:

```
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:


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

dateiSplit();
parseDatei();
```


----------



## kneitzel (3. Dez 2019)

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.


----------



## Bluedaishi (3. Dez 2019)

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


----------



## Bluedaishi (3. Dez 2019)

Habe es jetzt verstanden anhand deiner hilfe ..... und dem beispiel von heute Mittag


----------



## Bluedaishi (3. Dez 2019)

ich hatte mir das schon gedacht das ich mal wieder mein problem mit boolean habe true false ... da habe ich immer aussetzter


----------



## Bluedaishi (7. Dez 2019)

Guten Morgen eine Frage noch zu diesem Thema muss ich nicht noch ein lock.release ausführen damit die Datei wieder benutzt werden kann


----------



## mihe7 (7. Dez 2019)

Nein, da try-with-resources verwendet wurde.


----------



## Bluedaishi (7. Dez 2019)

Ich bekomme danach immer ein Datei Fehler aus dem externen Programm als wenn dort kein Zugriff darauf möglich ist


----------



## Bluedaishi (7. Dez 2019)

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


----------



## kneitzel (7. Dez 2019)

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.


----------



## Bluedaishi (7. Dez 2019)

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


----------



## kneitzel (7. Dez 2019)

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!


----------



## Bluedaishi (7. Dez 2019)

Ok ich schicke ihn in 10 min


----------



## Bluedaishi (7. Dez 2019)

```
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;
        }
    }
```


----------



## kneitzel (7. Dez 2019)

Das mit dem Lock gibt die Datei wieder frei. Was machst Du in

```
dateiSplit();
                    parseDatei();
```
mit der Datei?


----------



## Bluedaishi (7. Dez 2019)

dort wird die datei "DATEI.DAT" Eingelesen und in einzelne Dateien neu gespeichert


----------



## Bluedaishi (7. Dez 2019)

```
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);
        }

    }
```


----------



## kneitzel (7. Dez 2019)

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.


----------



## Bluedaishi (7. Dez 2019)

der bufferedreader wird auch geschlossen 
dann zeig mir mal bitte was du mit try-with-resources meinst


----------



## mrBrown (7. Dez 2019)

Bluedaishi hat gesagt.:


> der bufferedreader wird auch geschlossen


Aber nur *ein* BufferedWriter wird geschlossen. In der Schleife erzeugst du für jede Zeile einen BufferedWriter, aber nur den letzten schließt du.



Bluedaishi hat gesagt.:


> dann zeig mir mal bitte was du mit try-with-resources meinst





			The try-with-resources Statement (The Java™ Tutorials >                     Essential Java Classes > Exceptions)


----------



## Bluedaishi (7. Dez 2019)

ahh verstanden danke . meinst du das liegt daran das die datei.dat noch geöffnet ist obwohl ja der bufferedreader (b) unten geschlossen wird


----------



## kneitzel (7. Dez 2019)

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.


----------



## Bluedaishi (7. Dez 2019)

```
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


----------



## kneitzel (7. Dez 2019)

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.


```
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 ...


----------



## mrBrown (7. Dez 2019)

Bluedaishi hat gesagt.:


> ```
> while ((line = b.readLine()) != null) {
> if ((!line.startsWith("ENDE    NL")) & (!line.startsWith("FIN NC NL")) & (!line.startsWith("\004\033"))) {
> br.write(line + "\n");
> ...


Ne, jetzt passiert Unsinn, der auf den ersten Blick zu ner Exception führen dürfte.

Nimm try-with-resources, an einer sauberen Umsetzung scheiterst du ebenso wie die meisten anderen.


----------



## Bluedaishi (7. Dez 2019)

Ok verstehe ist das so kompliziert das ohne try-with-resources hinzukommen


----------



## mrBrown (7. Dez 2019)

Falls das ne Frage ist: Ja, ist es


----------



## Bluedaishi (7. Dez 2019)

Ok verstehe also ist mein Code also Mist das


----------



## mrBrown (7. Dez 2019)

Zumidest der Umgang mit Resourcen ist Mist, Ja


----------



## kneitzel (7. Dez 2019)

Bluedaishi hat gesagt.:


> Ok verstehe ist das so kompliziert das ohne try-with-resources hinzukommen


Nein, man muss nur verstehen, wie es geht.

Zugriff ohne try-with-resources ist immer nach einem einfachen Pattern:

```
SomeCloseableType variable;
try {
    variable = someInitialization();
    // Use variable here
} finally {
    try {
        if (variable != null) variable.close();
    } catch (Exception ex) {}
}
```

Und das ist dann halt ebenbürtig zu:

```
try (SomeCloseableType variable = someInitialization()) {
  // Use variable in here
}
```

Welche der beiden Varianten Du nutzen willst, ist Dir überlassen. Aber ohne eine entsprechende Lösung ist es in meinen Augen schlicht falsch!


----------



## mrBrown (7. Dez 2019)

JustNobody hat gesagt.:


> Nein, man muss nur verstehen, wie es geht.


Daran scheitern aber die meisten, grad wenn mehrere Resourcen geöffnet sind...


----------



## Bluedaishi (7. Dez 2019)

Ja ich  Ich werd es mal versuchen


----------



## Bluedaishi (7. Dez 2019)

Vielleicht brauche ich eure Hilfe nochmal hierbei


----------



## mihe7 (7. Dez 2019)

```

```



Bluedaishi hat gesagt.:


> Ja ich  Ich werd es mal versuchen


Nein. Du versuchst try-with-resources.


----------

