91

I'm trying to delete a file, after writing something in it, with FileOutputStream. This is the code I use for writing:

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

As it is seen, I flush and close the stream, but when I try to delete, file.delete() returns false.

I checked before deletion to see if the file exists, and: file.exists(), file.canRead(), file.canWrite(), file.canExecute() all return true. Just after calling these methods I try file.delete() and returns false.

Is there anything I've done wrong?

Lesmana
  • 25,663
  • 9
  • 82
  • 87
Jenny Smith
  • 2,987
  • 6
  • 29
  • 32
  • I forgot to mention that no exception is caught. – Jenny Smith Jun 13 '09 at 20:51
  • Are you sure the file isn't used by another process ? Did you lock it ? Does it work with deleteOnExit + exiting ? – instanceof me Jun 13 '09 at 20:55
  • What OS are you running on? Can you manually delete the file? Something might hold an open handle to the file. – akarnokd Jun 13 '09 at 20:56
  • How can I find out if it's used by another process? I didn't lock it. I can't use deleteOnExit method, because I need to delete the file and continue my applycation after that.The idea is that I try to emty a temporary folder, which is used to store files from a different folder for one session. When I press the open button on my applycation, it means the folder must be emptied, to make room for some other files. If I skip the part when I write in that file, it's ok, and I can delete it. – Jenny Smith Jun 13 '09 at 21:03
  • I'm on Win XP. I can delete the file manually just fine, but I can't run my applycation like that. It's supposed to be deleted from the application. – Jenny Smith Jun 13 '09 at 21:05
  • Maybe the file creation and file deletion runs parallel? Is your application a webapp with multiple users? You try to delete other's temp files? – akarnokd Jun 13 '09 at 21:07
  • Did the file exist prior to running that code, or was it created by this routine? – skaffman Jun 13 '09 at 21:39
  • Either way, it's better if you close the file in a finally block. – Ravi Wallau Nov 17 '09 at 20:52
  • Who owns the file? Are you creating it under one user context and trying to delete it in another? Your second process may not be allowed to delete the file. – Alan Moore Jun 13 '09 at 22:57
  • 1
    Can you please wrap your flush&close in a finally block? I know you've done this and it doesn't work, but it will add clarity to your question. – bharal Jul 23 '13 at 09:20
  • Everytime this occurs it has to do with unclosed streams or chmod – Stefan Sprenger Aug 05 '14 at 06:35

17 Answers17

104

Another bug in Java. I seldom find them, only my second in my 10 year career. This is my solution, as others have mentioned. I have nether used System.gc(). But here, in my case, it is absolutely crucial. Weird? YES!

finally
{
    try
    {
        in.close();
        in = null;
        out.flush();
        out.close();
        out = null;
        System.gc();
    }
    catch (IOException e)
    {
        logger.error(e.getMessage());
        e.printStackTrace();
    }
}
takrl
  • 6,356
  • 3
  • 60
  • 69
Da Martin
  • 1,041
  • 2
  • 7
  • 2
  • 8
    Although I did not open it with any kind of stream (just doing a `new File(path)`), I encountered the same problem and adding `System.gc()` before the `delete()` made it work! – ixM Mar 12 '13 at 08:15
  • doesn't wotk for me. The file i can't delete is a ZIP file of a downloadedFromURL file. The nice thing is that the downloaded file will be deleted. Any idea? – Andrea_86 Apr 23 '15 at 13:12
  • Worked for me. And @andreadi I never used FileChannel.map in my code. Seems that this bug got closed as unresolvable which makes me incredulous because the `System.gc` trick works every time. – Adam Burley May 19 '15 at 18:05
  • Single gc() might not help `System.gc(); result = file.delete(); if (!result){ Thread.sleep(100); System.gc(); result = file.delete(); }` – notes-jj Jun 26 '16 at 18:12
  • WoW thanks for posting your solution, this helped me a lot! I suffered a "file can not be deleted" Problem after migration from JDK7 to JDK9. Worked fine with JDK7, no longer worked with JDK9. Your top with calling System.gc() after the call of [...].close() solved this strange behaviour! Never would have figgured this out my self... I mean, Why Java, Why? – Ulathar Feb 20 '18 at 09:09
49

It was pretty odd the trick that worked. The thing is when I have previously read the content of the file, I used BufferedReader. After reading, I closed the buffer.

Meanwhile I switched and now I'm reading the content using FileInputStream. Also after finishing reading I close the stream. And now it's working.

The problem is I don't have the explanation for this.

I don't know BufferedReader and FileOutputStream to be incompatible.

jiaweizhang
  • 809
  • 1
  • 11
  • 28
Jenny Smith
  • 2,987
  • 6
  • 29
  • 32
  • 4
    I would argue it's a bug then: http://java.sun.com/javase/6/docs/api/java/io/BufferedReader.html#close() It says in there that the method should close the stream and any resources associated with it. I usually like to close all the streams in the inverted sequence (the last ones to be open are the first ones to be closed) using IOUtils.closeQuietly, but it tends to be overkill. – Ravi Wallau Jun 14 '09 at 05:55
  • 2
    I was having this exact problem I and I thought I was going crazy. Thanks for the solution! – Electrons_Ahoy Dec 13 '10 at 20:18
  • 14
    It's 2011 with JDK 7 and the problem still isn't fixed. I'm so glad I found this thread - I simply couldn't figure out what was wrong... – David Aug 17 '11 at 13:40
  • I had a very annoying problem with a file that I read and closed and then tried to delete. Nothing mentioned here helped. Then after an hour I discovered it was just the file rights, since the file had been created by another user :-D – runholen Aug 18 '14 at 13:16
  • Just a stab in the dark... Can you call `finalize()` to ensure cleanup? Or perhaps set `to = null`? See [Forcing Finalization and Garbage Collection](http://journals.ecs.soton.ac.uk/java/tutorial/java/system/garbage.html). – jww Aug 23 '14 at 21:54
  • jww: No, finalize() doesn't ensure cleanup, nor does setting to = null. I'm having the same issue and already tried those. But I just tried System.gc(), and it does work. In my case, I'm closing a file inputstream and then moving the file. When there is an exception reading the file, the exception is propagated to the point where I'm done dealing with the file, and that's where I close it - and in the exception cases, I'm not able to to move the file. But if I close the inputstream before propagating the exception, I can. I had wondered if the difference was gc happening in between. – Rebeccah Oct 01 '14 at 05:49
  • @David 2018 with JDK 8 and I still have the same problem when trying to do file cleanup using a shutdown hook. – Markus Ressel Feb 20 '18 at 19:28
  • I am with "try-with-resources" style with a `FileWriter` using a `FileOutputStream` created outside of `try`, and it is not auto-closed. I have to close it explicitly. – WesternGun Feb 15 '19 at 13:17
19

I tried this simple thing and it seems to be working.

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

It works for me.

If this does not work try to run your Java application with sudo if on linux and as administrator when on windows. Just to make sure Java has rights to change the file properties.

Kislay Sinha
  • 337
  • 2
  • 7
  • 1
    For this problem; generally people talk about setting references as null or calling system.gc(); but for me even after server restart files were not getting deleted !! But file.setWritable(true); just worked.. – Deepak Singhal Jun 06 '12 at 13:33
6

Before trying to delete/rename any file, you must ensure that all the readers or writers (for ex: BufferedReader/InputStreamReader/BufferedWriter) are properly closed.

When you try to read/write your data from/to a file, the file is held by the process and not released until the program execution completes. If you want to perform the delete/rename operations before the program ends, then you must use the close() method that comes with the java.io.* classes.

Gijs Overvliet
  • 2,643
  • 3
  • 28
  • 35
Sai Manoj
  • 81
  • 2
  • 3
3

As Jon Skeet commented, you should close your file in the finally {...} block, to ensure that it's always closed. And, instead of swallowing the exceptions with the e.printStackTrace, simply don't catch and add the exception to the method signature. If you can't for any reason, at least do this:

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

Now, question number #2:

What if you do this:

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

Would you be able to delete the file?

Also, files are flushed when they're closed. I use IOUtils.closeQuietly(...), so I use the flush method to ensure that the contents of the file are there before I try to close it (IOUtils.closeQuietly doesn't throw exceptions). Something like this:

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

So I know that the contents of the file are in there. As it usually matters to me that the contents of the file are written and not if the file could be closed or not, it really doesn't matter if the file was closed or not. In your case, as it matters, I would recommend closing the file yourself and treating any exceptions according.

Ravi Wallau
  • 10,416
  • 2
  • 25
  • 34
  • I tried the first thing - closing the output stream in the finally block. And it didn't work. What did happened if I tried to read after thatm is that I got a message saying the stream was closed. When switching and reading the file with FileInputReader, none of the "bad" thing described above happened. – Jenny Smith Jun 14 '09 at 16:33
2

If you are working in Eclipse IDE, that could mean that you haven't close the file in the previous launch of the application. When I had the same error message at trying to delete a file, that was the reason. It seems, Eclipse IDE doesn't close all files after termination of an application.

Gangnus
  • 24,044
  • 16
  • 90
  • 149
2

There is no reason you should not be able to delete this file. I would look to see who has a hold on this file. In unix/linux, you can use the lsof utility to check which process has a lock on the file. In windows, you can use process explorer.

for lsof, it's as simple as saying:

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

for process explorer you can use the find menu and enter the file name to show you the handle which will point you to the process locking the file.

here is some code that does what I think you need to do:

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

It works fine on OS X. I haven't tested it on windows but I suspect it should work on Windows too. I will also admit seeing some unexpected behavior on Windows w.r.t. file handling.

forsvarir
  • 10,749
  • 6
  • 46
  • 77
neesh
  • 5,167
  • 6
  • 29
  • 32
  • 1
    For windows, you can download the free Process Explorer from MS: http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx – akarnokd Jun 13 '09 at 21:10
1

Hopefully this will help. I came across similar problem where i couldn't delete my file after my java code made a copy of the content to the other folder. After extensive googling, i explicitly declared every single file operation related variables and called the close() method of each file operation object, and set them to NULL. Then, there is a function called System.gc(), which will clear up the file i/o mapping (i'm not sure, i just tell what is given on the web sites).

Here is my example 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();
    }
}
poh
  • 390
  • 4
  • 10
1

the answer is when you load the file, you need apply the "close" method, in any line of code, works to me

0

None of the solutions listed here worked in my situation. My solution was to use a while loop, attempting to delete the file, with a 5 second (configurable) limit for safety.

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

Using the above loop worked without having to do any manual garbage collecting or setting the stream to null, etc.

etech
  • 2,548
  • 1
  • 27
  • 24
  • What S.O. do you use? If you can have access to the STREAMS, close them, it will work. But if the file is "already" locked, then, you have a problem. – marcolopes Apr 01 '13 at 01:12
  • 1
    -1 looping in your code to delete a file isn't a great idea. Why not just use the gc() option that works? – bharal Jul 23 '13 at 09:19
  • @bharal Notice I state above that none of the other solutions (including gc()) worked in my particular case. While I agree using a while loop is not ideal, it may be an appropriate solution in certain circumstances. Adding an additional check to the code above, such as a timeout or max iterations variable, would be a good way to make the while loop safer. – etech Jul 25 '13 at 22:25
  • @etech if your file never existed though, you've just created an infinite loop. – bharal Jul 26 '13 at 21:33
0

The problem could be that the file is still seen as opened and locked by a program; or maybe it is a component from your program that it had been opened in, so you have to ensure you use the dispose() method to solve that problem. i.e. JFrame frame; .... frame.dispose();

Winnifred
  • 1,202
  • 1
  • 8
  • 10
0

You have to close all of the streams or use try-with-resource block

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;
}
feech
  • 404
  • 4
  • 15
0

if file.delete() is sending false then in most of the cases your Bufferedreader handle will not be closed. Just close and it seems to work for me normally.

Piyush
  • 388
  • 1
  • 6
  • 21
0

I had the same problem on Windows. I used to read the file in scala line by line with

Source.fromFile(path).getLines()

Now I read it as a whole with

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

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

which closes the file properly after reading and now

new File(path).delete

works.

sbtpr
  • 541
  • 5
  • 18
0

FOR Eclipse/NetBeans

Restart your IDE and run your code again this is only trick work for me after one hour long struggle.

Here is my code:

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

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

Output:

Delete

Omore
  • 614
  • 6
  • 18
0

There was a problem once in ruby where files in windows needed an "fsync" to actually be able to turn around and re-read the file after writing it and closing it. Maybe this is a similar manifestation (and if so, I think a windows bug, really).

rogerdpack
  • 62,887
  • 36
  • 269
  • 388
0

Another corner case that this could happen: if you read/write a JAR file through a URL and later try to delete the same file within the same JVM session.

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!

Reason is that the internal JAR file handling logic of Java, tends to cache JarFile entries:

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

And each JarFile (rather, the underlying ZipFile structure) would hold a handle to the file, right from the time of construction up until close() is invoked:

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;

There's a good explanation on this NetBeans issue.


Apparently there are two ways to "fix" this:

  • You can disable the JAR file caching - for the current URLConnection, or for all future URLConnections (globally) in the current JVM session:

    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 WARNING!] You can manually purge the JarFile from the cache when you are done with it. The cache manager sun.net.www.protocol.jar.JarFileFactory is package-private, but some reflection magic can get the job done for you:

    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.
    

Please note: All this is based on Java 8 codebase (1.8.0_144); they may not work with other / later versions.

Janaka Bandara
  • 1,024
  • 1
  • 12
  • 27