File.Delete () gibt false zurück, obwohl File.Exists (), file.canRead (), file.canWrite (), file.canExecute () all true zurück

StackOverflow https://stackoverflow.com/questions/991489

  •  13-09-2019
  •  | 
  •  

Frage

Ich versuche, eine Datei zu löschen, nachdem etwas in ihm zu schreiben, mit FileOutputStream. Dies ist der Code, den ich zum Schreiben verwenden:

private void writeContent(File file, String fileContent) {
    FileOutputStream to;
    try {
        to = new FileOutputStream(file);
        to.write(fileContent.getBytes());
        to.flush();
        to.close();
    } catch (FileNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

Wie zu sehen ist, ich spüle und den Strom in der Nähe, aber wenn ich versuche zu löschen, file.delete() false zurück.

Ich habe vor dem Löschen zu sehen, ob die Datei vorhanden ist, und: file.exists(), file.canRead(), file.canWrite(), file.canExecute() alles wahr zurück. Kurz nach diesen Methoden aufrufen Ich versuche file.delete() und gibt false zurück.

Gibt es etwas, was ich falsch gemacht habe?

War es hilfreich?

Lösung 2

Es war ziemlich seltsam der Trick, der funktioniert. Die Sache ist, wenn ich vorher den Inhalt der Datei zu lesen, habe ich BufferedReader. Nach der Lektüre, schloss ich den Puffer.

Inzwischen wechselte ich und jetzt den Inhalt mit FileInputStream lese ich. Auch nach dem Lesen Finishing schließe ich den Strom. Und jetzt ist es funktioniert.

Das Problem ist, ich habe nicht die Erklärung dafür.

Ich weiß nicht, BufferedReader und FileOutputStream unvereinbar sein.

Andere Tipps

Ein weiterer Fehler in Java. Ich finde sie selten, nur meinen zweiter in meiner 10-jährigen Karriere. Dies ist meine Lösung, wie andere erwähnt haben. Ich habe nether verwendet System.gc(). Aber hier, in meinem Fall ist es absolut entscheidend. Seltsam? JA!

finally
{
    try
    {
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        System.gc();
    }
    catch (IOException e)
    {
        logger.error(e.getMessage());
        e.printStackTrace();
    }
}

Ich habe versucht, diese einfache Sache, und es scheint zu funktionieren.

file.setWritable(true);
file.delete();

Es funktioniert für mich.

Wenn dieser Versuch nicht funktioniert Ihre Java-Anwendung mit sudo ausgeführt werden, wenn auf Linux und als Administrator unter Windows. Nur um sicherzugehen Java hat Rechte die Dateieigenschaften zu ändern.

Vor der Datei zu löschen / umbenennen versuchen, müssen Sie sicherstellen, dass alle Leser oder Autoren (zB: BufferedReader / InputStreamReader / BufferedWriter). Ordnungsgemäß geschlossen

Wenn Sie versuchen, Ihre Daten zu lesen / schreiben von / in eine Datei, die Datei von dem Prozess gehalten wird und erst freigegeben, wenn die Programmausführung abgeschlossen ist. Wenn Sie das Löschen / Umbenennen Operationen ausführen möchten, bevor das Programm beendet wird, dann müssen Sie die close() Methode verwenden, die mit den java.io.* Klassen kommt.

Wie Jon Skeet kommentiert, sollten Sie Ihre Datei im finally {...} Block, schließen, um sicherzustellen, dass es immer geschlossen ist. Und anstatt die Ausnahmen mit dem e.printStackTrace Schlucken, einfach nicht fangen und die Ausnahme von der Methodensignatur hinzuzufügen. Wenn Sie aus irgendeinem Grund nicht kann, zumindest dies tun:

catch(IOException ex) {
    throw new RuntimeException("Error processing file XYZ", ex);
}

Jetzt Frage Nummer 2:

Was ist, wenn Sie dies tun:

...
to.close();
System.out.println("Please delete the file and press <enter> afterwards!");
System.in.read();
...

Möchten Sie in der Lage sein, die Datei zu löschen?

Auch Dateien sind gerötet, wenn sie geschlossen sind. Ich benutze IOUtils.closeQuietly (...), so dass ich die Flush-Methode, um sicherzustellen, dass der Inhalt der Datei gibt es, bevor ich versuche, es zu schließen (IOUtils.closeQuietly keine Ausnahmen werfen). So etwas wie folgt aus:

...
try {
    ...
    to.flush();
} catch(IOException ex) {
    throw new CannotProcessFileException("whatever", ex);
} finally {
    IOUtils.closeQuietly(to);
}

So weiß ich, dass der Inhalt der Datei drin ist. Wie es in der Regel für mich zählt, dass der Inhalt der Datei geschrieben werden und nicht, wenn die Datei geschlossen werden kann oder nicht, ist es wirklich nicht, wenn die Datei geschlossen wurde oder nicht. In Ihrem Fall, da es wichtig ist, würde ich empfehlen, die Datei selbst zu schließen und die Behandlung alle Ausnahmen nach.

Es gibt keinen Grund, warum Sie sollten nicht in der Lage sein, diese Datei zu löschen. Ich würde schauen, um zu sehen, die einen Einfluß auf diese Datei hat. In Unix / Linux können Sie die lsof-Dienstprogramm zu überprüfen, welcher Prozess eine Sperre auf die Datei hat. In Windows können Sie Process Explorer verwenden.

für lsof, es ist so einfach wie zu sagen:

lsof /path/and/name/of/the/file

für Process Explorer können Sie das Suchmenü verwenden und geben Sie den Dateinamen, den Sie den Griff zu zeigen, die Sie an den Prozess Punkt wird die Datei sperren.

Hier ist ein Code, der tut, was ich denke, was Sie tun müssen:

FileOutputStream to;

try {
    String file = "/tmp/will_delete.txt";
    to = new FileOutputStream(file );
    to.write(new String("blah blah").getBytes());
    to.flush();
    to.close();
    File f = new File(file);
    System.out.print(f.delete());
} catch (FileNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

Es funktioniert auf OS X. Ich kann es auf windows nicht getestet, aber ich vermute, es sollte auch unter Windows arbeiten. Ich werde auch ein unerwartetes Verhalten auf Windows w.r.t. admit sehen Datei-Handling.

Wenn Sie in Eclipse IDE arbeiten, bedeutet, dass könnte, dass Sie die Datei nicht in dem vorherigen Start der Anwendung schließen haben. Wenn ich mir versuchen, die gleiche Fehlermeldung hatte eine Datei zu löschen, das war der Grund. Es scheint, Eclipse-IDE nicht alle Dateien nach Beendigung einer Anwendung schließen.

Dies wird hoffentlich helfen. Ich stieß auf ähnliches Problem, wo ich meine Datei nicht löschen konnte nach meinem Java-Code, der eine Kopie des Inhalts in den anderen Ordnern aus. Nach umfangreichen googeln, erklärte ich ausdrücklich jede einzelne Dateioperation bezogenen Variablen und die Methode close () jeder Dateioperation Objekt aufgerufen und stellte sie NULL zu. Dann gibt es eine Funktion System.gc () aufgerufen, die die Datei aufklären wird i / o-Mapping (ich bin nicht sicher, ich nur sagen, was auf den Webseiten gegeben ist).

Hier ist mein Beispielcode:

public void start() {
    File f = new File(this.archivePath + "\\" + this.currentFile.getName());
    this.Copy(this.currentFile, f);

    if(!this.currentFile.canWrite()){
        System.out.println("Write protected file " +
           this.currentFile.getAbsolutePath());

        return;
    }


    boolean ok = this.currentFile.delete();
    if(ok == false){
        System.out.println("Failed to remove " + this.currentFile.getAbsolutePath());
        return;
    }
}

private void Copy(File source, File dest) throws IOException {
    FileInputStream fin;
    FileOutputStream fout;
    FileChannel cin = null, cout = null;
    try {
        fin = new FileInputStream(source);
        cin = fin.getChannel();
        fout = new FileOutputStream(dest);
        cout = fout.getChannel();

        long size = cin.size();
        MappedByteBuffer buf = cin.map(FileChannel.MapMode.READ_ONLY, 0, size);

        cout.write(buf);
        buf.clear();
        buf = null;

        cin.close();
        cin = null;

        fin.close();
        fin = null;

        cout.close();
        cout = null;

        fout.close();
        fout = null;

        System.gc();

    } catch (Exception e){
        this.message = e.getMessage();
        e.printStackTrace();
    }
}

ist die Antwort, wenn Sie die Datei laden, müssen Sie die „Schließen“ Methode anwenden, in jeder Codezeile, arbeitet mir

Es war einmal ein Problem in Ruby, wo die Dateien in Windows benötigt eine „fsync“ tatsächlich in der Lage sein, sich umzudrehen und wieder lesen Sie die Datei, nachdem er das Schreiben und Schließen. Vielleicht ist dies eine ähnliche Erscheinung (und wenn ja, denke ich, einen Windows-Fehler, wirklich).

Keine der aufgeführten Lösungen hier arbeitete in meiner Situation. Meine Lösung war eine while-Schleife zu verwenden, versuchen, die Datei zu löschen, mit einem 5 Sekunden (konfigurierbar) Grenzwerte für die Sicherheit.

File f = new File("/path/to/file");

int limit = 20; //Only try for 5 seconds, for safety
while(!f.delete() && limit > 0){
    synchronized(this){
        try {
            this.wait(250); //Wait for 250 milliseconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    limit--;
}

die obige Schleife gearbeitet ohne manuelle Mülleinsammlungs zu tun zu haben oder den Strom auf null einstellen, etc.

Das Problem könnte sein, dass die Datei noch von einem Programm wie geöffnet und verriegelt zu sehen ist; oder vielleicht ist es eine Komponente von Ihrem Programm, das es in geöffnet worden war, so müssen Sie sicherstellen, dass Sie die dispose() Methode verwenden, um das Problem zu lösen. das heißt JFrame frame; .... frame.dispose();

Sie haben alle Ströme zu schließen oder nutzen versuchen-mit-Ressourcenblock

static public String head(File file) throws FileNotFoundException, UnsupportedEncodingException, IOException
{
    final String readLine;
    try (FileInputStream fis = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(fis, "UTF-8");
            LineNumberReader lnr = new LineNumberReader(isr))
    {
        readLine = lnr.readLine();
    }
    return readLine;
}

Wenn File.Delete () falsch sendet dann in den meisten Fällen Ihr BufferedReader Griff wird nicht geschlossen werden. Nur enge und es scheint normal für mich zu arbeiten.

Ich hatte das gleiche Problem unter Windows. Früher habe ich die Datei in scala Zeile für Zeile lesen mit

Source.fromFile(path).getLines()

Nun lese ich es als Ganzes mit

import org.apache.commons.io.FileUtils._

// encoding is null for platform default
val content=readFileToString(new File(path),null.asInstanceOf[String])

, die die Datei richtig nach dem Lesen und jetzt schließt

new File(path).delete

funktioniert.

  

Eclipse / NetBeans

Ihre IDE neu starten und den Code erneut ausführen, dies ist nur Trick Arbeit für mich nach einer Stunde langen Kampf.

Hier ist mein Code:

File file = new File("file-path");
if(file.exists()){
  if(file.delete()){
     System.out.println("Delete");
  }
  else{

       System.out.println("not delete");
  }
}

Ausgang:

Löschen

Eine weitere Ecke Fall, dass dies passieren könnte. Wenn Sie lesen / eine JAR-Datei durch einen URL schreiben und später versuchen, die gleiche Datei innerhalb der gleichen JVM-Sitzung löschen

File f = new File("/tmp/foo.jar");
URL j = f.toURI().toURL();

URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
URLConnection c = u.openConnection();

// open a Jar entry in auto-closing manner
try (InputStream i = c.getInputStream()) {

    // just read some stuff; for demonstration purposes only
    byte[] first16 = new byte[16];
    i.read(first16);
    System.out.println(new String(first16));
}

// ...

// i is now closed, so we should be good to delete the jar; but...
System.out.println(f.delete());     // says false!

Der Grund hierfür ist, dass die interne JAR-Datei Logik der Java Handhabung neigt JarFile Einträge zwischenzuspeichern:

// inner class of `JarURLConnection` that wraps the actual stream returned by `getInputStream()`

class JarURLInputStream extends FilterInputStream {
    JarURLInputStream(InputStream var2) {
        super(var2);
    }

    public void close() throws IOException {
        try {
            super.close();
        } finally {

            // if `getUseCaches()` is set, `jarFile` won't get closed!

            if (!JarURLConnection.this.getUseCaches()) {
                JarURLConnection.this.jarFile.close();
            }
        }
    }
}

Und jedes JarFile (besser gesagt, die zugrunde liegende Struktur ZipFile) würde einen Griff in die Datei direkt aus der Zeit des Aufbaus bis halten, bis close() aufgerufen wird:

public ZipFile(File file, int mode, Charset charset) throws IOException {
    // ...

    jzfile = open(name, mode, file.lastModified(), usemmap);

    // ...
}

// ...

private static native long open(String name, int mode, long lastModified,
                                boolean usemmap) throws IOException;

Es gibt eine gute Erklärung auf dieser NetBeans Ausgabe .


Anscheinend gibt es zwei Möglichkeiten, zu „reparieren“ folgendermaßen aus:

  • Sie können den JAR-Datei-Caching deaktivieren - für den aktuellen URLConnection, oder für alle zukünftigen URLConnections (global) in der aktuellen JVM-Sitzung:

    URL u = new URL("jar:" + j + "!/META-INF/MANIFEST.MF");
    URLConnection c = u.openConnection();
    
    // for only c
    c.setUseCaches(false);
    
    // globally; for some reason this method is not static,
    // so we still need to access it through a URLConnection instance :(
    c.setDefaultUseCaches(false);
    
  • [HACK ACHTUNG!] Sie können manuell den JarFile aus dem Cache löschen, wenn Sie mit ihm fertig sind. Der Cache-Manager sun.net.www.protocol.jar.JarFileFactory ist Paket-private, aber einige Reflexion Magie den Job zu erledigen für Sie bekommen können:

    class JarBridge {
    
        static void closeJar(URL url) throws Exception {
    
            // JarFileFactory jarFactory = JarFileFactory.getInstance();
            Class<?> jarFactoryClazz = Class.forName("sun.net.www.protocol.jar.JarFileFactory");
            Method getInstance = jarFactoryClazz.getMethod("getInstance");
            getInstance.setAccessible(true);
            Object jarFactory = getInstance.invoke(jarFactoryClazz);
    
            // JarFile jarFile = jarFactory.get(url);
            Method get = jarFactoryClazz.getMethod("get", URL.class);
            get.setAccessible(true);
            Object jarFile = get.invoke(jarFactory, url);
    
            // jarFactory.close(jarFile);
            Method close = jarFactoryClazz.getMethod("close", JarFile.class);
            close.setAccessible(true);
            //noinspection JavaReflectionInvocation
            close.invoke(jarFactory, jarFile);
    
            // jarFile.close();
            ((JarFile) jarFile).close();
        }
    }
    
    // and in your code:
    
    // i is now closed, so we should be good to delete the jar
    JarBridge.closeJar(j);
    System.out.println(f.delete());     // says true, phew.
    

Bitte beachten Sie: Das ist alles basierend auf Java 8 Code-Basis (1.8.0_144); sie dürfen nicht mit anderen / späteren Versionen arbeiten.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top