File.Delete () restituisce false, anche se File.Exists (), file.canRead (), file.canWrite (), file.canExecute () tutto restituiscono true

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

  •  13-09-2019
  •  | 
  •  

Domanda

Sto cercando di eliminare un file, dopo aver scritto qualcosa in esso, con FileOutputStream. Questo è il codice che uso per la scrittura:

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

Come si vede, Arrossisco e chiudere il flusso, ma quando provo a cancellare, file.delete() restituisce false.

Ho controllato prima della cancellazione, per vedere se il file esiste, e: file.exists(), file.canRead(), file.canWrite(), file.canExecute() restituiscono tutte vere. Subito dopo si chiamano questi metodi provo file.delete() e restituisce falso.

C'è qualcosa che ho fatto di sbagliato?

È stato utile?

Soluzione 2

E 'stato abbastanza strano il trucco che ha funzionato. Il fatto è che quando ho già letto il contenuto del file, ho usato BufferedReader. Dopo la lettura, ho chiuso il buffer.

Nel frattempo ho cambiato e adesso sto leggendo il contenuto utilizzando FileInputStream. Anche dopo aver terminato la lettura chiudo il flusso. E ora si sta lavorando.

Il problema è che non ho la spiegazione per questo.

Non so BufferedReader e FileOutputStream incompatibili.

Altri suggerimenti

Un altro bug in Java. Raramente li trovo, solo il mio secondo nella mia carriera di 10 anni. Questa è la mia soluzione, come altri hanno detto. Ho usato inferi System.gc(). Ma qui, nel mio caso, è assolutamente cruciale. Strano? SÌ!

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

Ho provato questa cosa semplice e sembra funzionare.

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

Funziona per me.

Se questo non funziona tenta di eseguire l'applicazione Java con sudo se su Linux e come amministratore quando sulle finestre. Giusto per assicurarsi che Java ha il diritto di modificare le proprietà del file.

Prima di provare a cancellare / rinominare qualsiasi tipo di file, è necessario assicurarsi che tutti i lettori o scrittori (per es: BufferedReader / InputStreamReader / BufferedWriter). Siano ben chiusi

Quando si tenta di leggere / scrivere i dati da / a un file, il file viene tenuto dal processo e non rilasciato fino a quando l'esecuzione del programma viene completata. Se si desidera eseguire la cancellazione / rinomina operazioni prima che il programma termina, quindi è necessario utilizzare il metodo close() che viene fornito con le classi java.io.*.

Come ha commentato Jon Skeet, si dovrebbe chiudere il file nel blocco finally {...}, al fine di garantire che è sempre chiuso. E, invece di deglutire le eccezioni con l'e.printStackTrace, semplicemente non catturare e aggiungere l'eccezione per la firma del metodo. Se non è possibile, per qualsiasi motivo, almeno fare questo:

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

Ora, domanda numero # 2:

Che cosa succede se si esegue questa operazione:

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

Vuoi essere in grado di eliminare il file?

Inoltre, i file vengono scaricati quando sono chiusi. Io uso IOUtils.closeQuietly (...), per cui uso il metodo flush al fine di garantire che il contenuto del file ci sono prima di provare per chiuderla (IOUtils.closeQuietly non genera eccezioni). Qualcosa di simile a questo:

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

Quindi so che il contenuto del file sono lì. Come è solito importante per me che il contenuto del file sono scritte e non se il file potrebbe essere chiusa o no, in realtà non importa se il file è stato chiuso o meno. Nel tuo caso, come è importante, mi sento di raccomandare la chiusura del file di se stessi e il trattamento di eventuali eccezioni secondo.

Non v'è alcuna ragione per cui non si dovrebbe essere in grado di eliminare questo file. Vorrei guardare per vedere chi ha una presa su questo file. In Unix / Linux, è possibile utilizzare l'utility lsof per controllare quale processo ha un blocco sul file. In Windows, è possibile utilizzare Process Explorer.

per lsof, è semplice come dire:

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

per Process Explorer è possibile utilizzare il menu Trova e immettere il nome del file per mostrarvi la maniglia che si punta al processo di blocco del file.

Un po 'di codice che fa quello che penso che devi fare:

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

Funziona bene su OS X. Non ho ancora testato su Windows ma ho il sospetto che dovrebbe funzionare anche su Windows. Io ammettere anche vedendo alcuni comportamenti imprevisti in Windows w.r.t. la gestione dei file.

Se si sta lavorando in Eclipse IDE, che potrebbe significare che non hai chiudere il file nel lancio precedente dell'applicazione. Quando ho avuto lo stesso messaggio di errore a cercare di eliminare un file, che era la ragione. Sembra, Eclipse non chiude tutti i file dopo la cessazione di un'applicazione.

Speriamo che questo vi aiuterà. Mi sono imbattuto in un problema simile in cui non ho potuto cancellare il mio file dopo il mio codice Java ha fatto una copia del contenuto in un'altra cartella. Dopo ampia googling, ho dichiarato in modo esplicito ogni singolo variabili relativa operazione di file e chiamato il metodo close () di ciascun oggetto un'operazione di file, e impostarle su null. Poi, c'è una funzione chiamata System.gc (), che sarà chiarire il file I / O mapping (non sono sicuro, ho solo detto ciò che è dato sui siti web).

Ecco il mio codice di esempio:

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

la risposta è quando si carica il file, è necessario applicare il metodo "close", in ogni riga di codice, lavora per me

C'è stato un problema, una volta in Ruby in cui i file in Windows bisogno di un "fsync" per essere effettivamente in grado di girarsi e ri-leggere il file dopo averlo scritto e chiusura. Forse questa è una manifestazione simile (e se sì, penso che un bug di Windows, in realtà).

Nessuna delle soluzioni elencate qui lavorato nella mia situazione. La mia soluzione era quella di utilizzare un ciclo while, il tentativo di eliminare il file, con un 5 secondo limite (configurabile) per la sicurezza.

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

Uso ciclo precedente lavorato senza dover fare qualsiasi raccolta rifiuti manuale o modificando il flusso a zero, ecc.

Il problema potrebbe essere che il file è ancora visto come aperto e bloccato da un programma; o forse si tratta di un componente dal vostro programma che era stato aperto in, in modo da avere per assicurarsi di utilizzare il metodo dispose() per risolvere il problema. cioè JFrame frame; .... frame.dispose();

È necessario chiudere tutti i corsi d'acqua o utilizzare try-with-risorsa blocco

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

se File.Delete () sta inviando falso quindi nella maggior parte dei casi il vostro maniglia BufferedReader non verrà chiuso. Proprio vicino e sembra funzionare per me normalmente.

Ho avuto lo stesso problema su Windows. Ho usato per leggere il file in linea scala per riga con

Source.fromFile(path).getLines()

Ora ho letto nel suo complesso con

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

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

che chiude il file in modo corretto dopo aver letto e ora

new File(path).delete

opere.

  

Per Eclipse / NetBeans

Riavviare l'IDE ed eseguire il codice ancora una volta questo è solo il lavoro trucco per me, dopo lunga lotta un'ora.

Qui è il mio codice:

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

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

Output:

Elimina

Un altro caso d'angolo che questo potrebbe accadere:. Se si legge / scrive un file JAR attraverso un URL e poi cercare di eliminare lo stesso file all'interno della stessa sessione JVM

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!

Il motivo è che la logica di gestione di Java file JAR interno, tende a memorizzare nella cache le voci JarFile:

// 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();
            }
        }
    }
}

E ogni JarFile (piuttosto, la struttura ZipFile sottostante) terrebbe una maniglia per il file, fin dal momento della costruzione fino a quando viene richiamato close():

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;

C'è una buona spiegazione su questo NetBeans problema .


A quanto pare ci sono due modi per "sistemare" in questo modo:

  • È possibile disattivare il file JAR caching - per il URLConnection corrente, o per tutti URLConnections futuri (a livello mondiale) nella sessione corrente JVM:

    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 ATTENZIONE!] È possibile eliminare manualmente il JarFile dalla cache quando si è fatto con esso. La cache direttore sun.net.www.protocol.jar.JarFileFactory è il pacchetto-privato, ma una certa magia riflessione può ottenere il lavoro fatto per voi:

    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.
    

Nota: Tutto questo si basa su Java 8 codebase (1.8.0_144); essi potrebbero non funzionare con altre versioni / successive.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top