web-dev-qa-db-fra.com

file.delete () renvoie false même si file.exists (), file.canRead (), file.canWrite (), file.canExecute () retournent tous la valeur true

J'essaie de supprimer un fichier après y avoir écrit quelque chose avec FileOutputStream. C'est le code que j'utilise pour écrire:

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

Comme on le voit, je vide et ferme le flux, mais lorsque je tente de supprimer, file.delete() renvoie false.

J'ai vérifié avant la suppression si le fichier existait et: file.exists(), file.canRead(), file.canWrite(), file.canExecute() retournent tous la valeur true. Juste après avoir appelé ces méthodes, j'essaie file.delete() et renvoie false.

Y a-t-il quelque chose que j'ai mal fait?

86
Jenny Smith

C'était assez étrange le truc qui a fonctionné. Le problème, c’est que lorsque j’avais déjà lu le contenu du fichier, j’utilisais BufferedReader. Après avoir lu, j'ai fermé le tampon.

En attendant, j'ai basculé et maintenant je lis le contenu en utilisant FileInputStream. Aussi, après avoir fini de lire, je ferme le flux. Et maintenant ça marche.

Le problème est que je n'ai pas d'explication à cela.

Je ne sais pas que BufferedReader et FileOutputStream soient incompatibles.

46
Jenny Smith

Un autre bug en Java. Je les trouve rarement, seulement ma deuxième en 10 ans de carrière. C'est ma solution, comme d'autres l'ont mentionné. Je n'ai jamais utilisé System.gc(). Mais ici, dans mon cas, c'est absolument crucial. Bizarre? OUI!

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

J'ai essayé cette chose simple et cela semble fonctionner.

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

Ça marche pour moi.

Si cela ne fonctionne pas, essayez d'exécuter votre application Java avec Sudo si elle est sous Linux et en tant qu'administrateur si vous êtes sous Windows. Juste pour vous assurer que Java a le droit de changer les propriétés du fichier.

17
Kislay Sinha

Avant d'essayer de supprimer/renommer un fichier, vous devez vous assurer que tous les lecteurs ou rédacteurs (par exemple: BufferedReader/InputStreamReader/BufferedWriter) sont correctement fermés.

Lorsque vous essayez de lire/écrire vos données depuis/dans un fichier, le fichier est conservé par le processus et n'est pas publié tant que l'exécution du programme n'est pas terminée. Si vous souhaitez effectuer les opérations de suppression/modification de nom avant la fin du programme, vous devez utiliser la méthode close() fournie avec la commande Java.io.* Des classes.

5
Sai Manoj

Comme Jon Skeet a commenté, vous devez fermer votre fichier dans le bloc finally {...} pour vous assurer qu'il est toujours fermé. Et au lieu d’avaler les exceptions avec e.printStackTrace, ne capturez pas et n’ajoutez pas l’exception à la signature de la méthode. Si vous ne pouvez pas pour une raison quelconque, faites au moins ceci:

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

Maintenant, question numéro 2:

Et si tu fais ça:

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

Seriez-vous capable de supprimer le fichier?

De plus, les fichiers sont vidés quand ils sont fermés. J'utilise IOUtils.closeQuietly (...), j'utilise donc la méthode flush pour m'assurer que le contenu du fichier est présent avant d'essayer de le fermer (IOUtils.closeQuietly ne lève pas d'exceptions). Quelque chose comme ça:

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

Je sais donc que le contenu du fichier est là. Comme il est généralement important pour moi que le contenu du fichier soit écrit et non de savoir si le fichier peut être fermé ou non, peu importe que le fichier soit fermé ou non. Dans votre cas, peu importe la situation, je vous recommande de fermer le fichier vous-même et de traiter les éventuelles exceptions en conséquence.

3
Ravi Wallau

Si vous travaillez dans Eclipse IDE, cela pourrait signifier que vous n'avez pas fermé le fichier lors du lancement précédent de l'application. Quand j'ai eu le même message d'erreur en essayant de supprimer un fichier, c'était la raison. Il semble qu'Eclipse IDE ne ferme pas tous les fichiers après la fermeture d'une application.

2
Gangnus

Il n'y a aucune raison pour que vous ne puissiez pas supprimer ce fichier. Je regarderais pour voir qui a une prise sur ce dossier. Sous unix/linux, vous pouvez utiliser l'utilitaire lsof pour vérifier quel processus verrouille le fichier. Dans Windows, vous pouvez utiliser l’explorateur de processus.

pour lsof, c'est aussi simple que de dire:

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

pour Process Explorer, vous pouvez utiliser le menu de recherche et entrer le nom du fichier pour vous montrer le descripteur qui vous indiquera le processus de verrouillage du fichier.

voici un code qui fait ce que je pense que vous devez faire:

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

Cela fonctionne très bien sous OS X. Je ne l'ai pas testé sous Windows, mais je pense que cela devrait également fonctionner sous Windows. Je vais aussi admettre avoir eu un comportement inattendu sur Windows w.r.t. la gestion des fichiers.

2
neesh

la réponse est lorsque vous chargez le fichier, vous devez appliquer la méthode "close", quelle que soit la ligne de code, qui fonctionne pour moi

1
user3200921

Espérons que cela aidera. Je suis tombé sur un problème similaire dans lequel je ne pouvais pas supprimer mon fichier après mon Java en a fait une copie du contenu dans l'autre dossier. Après une recherche approfondie, j'ai explicitement déclaré chaque variable liée à l'opération de fichier. et appelé la méthode close () de chaque objet opération de fichier et définissez-les sur NULL. Ensuite, il existe une fonction appelée System.gc (), qui efface le mappage des entrées/sorties sur le fichier (je ne suis pas sûr, i Dites simplement ce qui est donné sur les sites Web).

Voici mon exemple de code:

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

si file.delete () envoie la valeur false, dans la plupart des cas, votre descripteur Bufferedreader ne sera pas fermé. Il suffit de fermer et cela semble fonctionner pour moi normalement.

0
Piyush

POUR Eclipse/NetBeans

Redémarrez votre IDE et exécutez votre code à nouveau. Ce n'est qu'un travail piège pour moi après une heure de lutte.

Voici mon code:

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

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

Sortie:

Effacer

0
Omore

Vous devez fermer tous les flux ou utiliser le bloc try-with-resource

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

J'ai eu le même problème sous Windows. J'avais l'habitude de lire le fichier dans scala ligne par ligne avec

Source.fromFile(path).getLines()

Maintenant je le lis dans son ensemble avec

import org.Apache.commons.io.FileUtils._

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

qui ferme correctement le fichier après lecture et maintenant

new File(path).delete

travaux.

0
sbtpr

Le problème pourrait être que le fichier est toujours considéré comme ouvert et verrouillé par un programme; ou peut-être est-ce un composant de votre programme dans lequel il a été ouvert, vous devez donc vous assurer que vous utilisez la méthode dispose() pour résoudre ce problème. c'est-à-dire JFrame frame; .... frame.dispose();

0
Winnifred

Aucune des solutions énumérées ici n'a fonctionné dans ma situation. Ma solution consistait à utiliser une boucle while, en essayant de supprimer le fichier, avec une limite de 5 secondes (configurable) pour la sécurité.

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

L'utilisation de la boucle ci-dessus a fonctionné sans avoir à effectuer de nettoyage manuel ni à définir le flux sur null, etc.

0
etech

Il y avait un problème une fois dans Ruby où les fichiers dans Windows avaient besoin d'un "fsync" pour pouvoir réellement se retourner et relire le fichier après l'avoir écrit et fermé. Peut-être qu'il s'agit d'un problème similaire. manifestation (et si oui, je pense un bug de Windows, vraiment).

0
rogerdpack

Cela pourrait également se produire si vous lisiez/écrivez un fichier JAR via un URL et tentez ultérieurement de supprimer le même fichier dans la même session 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!

La raison en est que la logique interne de traitement des fichiers JAR de Java tend à mettre en cache les entrées 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();
            }
        }
    }
}

Et chaque JarFile (plutôt la structure ZipFile sous-jacente) contiendrait un descripteur du fichier, à partir du moment de la construction jusqu'à ce que close() soit invoqué:

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;

Il y a une bonne explication sur ce problème de NetBeans .


Apparemment, il existe deux façons de "réparer" ceci:

  • Vous pouvez désactiver la mise en cache du fichier JAR - pour le URLConnection actuel ou pour tous les futurs URLConnections (globalement) de la session JVM actuelle:

    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);
     Vous pouvez purger manuellement le JarFile du cache lorsque vous avez terminé. Le gestionnaire de cache Sun.net.www.protocol.jar.JarFileFactory Est privé à l'emballage, mais une réflexion magique peut vous permettre de faire le travail à votre place:

    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.
    

Remarque: Tout ceci est basé sur Java 8 codebase (1.8.0_144); Ils ne peuvent pas travailler avec d'autres/versions ultérieures.

0
Janaka Bandara