0

I've written a program that decompresses a ZIP archive, then recursively decompresses or extracts archives found in it. The archives within the ZIP may be tar or ZIP archives and I can extract them just fine.

After extracting the inner archives within some new directory, I want to delete them. This works just fine for tar archives, but for some reason it will not work for ZIP archives. I've closed all streams, and should deletion fail I use deleteOnExit as a fail-safe, but that doesn't work either.

    try (ArchiveInputStream ais =
         asFactory.createArchiveInputStream(
           new BufferedInputStream(
             new FileInputStream(archive)))) {

        System.out.println("Extracting!");
        ArchiveEntry ae;
        while ((ae = ais.getNextEntry()) != null) {
            if (ae.isDirectory()) {
                File dir = new File(archive.getParentFile(), ae.getName());
                dir.mkdirs();
                continue;
            }

            File f = new File(archive.getParentFile(), ae.getName());
            File parent = f.getParentFile();
            parent.mkdirs();
            try (OutputStream os = new FileOutputStream(f)) {
                IOUtils.copy(ais, os);
                os.close();
            } catch (IOException innerIoe) {
                ...
            }
        }

        ais.close();
        if (!archive.delete()) {
            System.out.printf("Could not remove archive %s%n",
                               archive.getName());
            archive.deleteOnExit();
        }
    } catch (IOException ioe) {
        ...
    }

There should be no open streams, unless closing the ArchiveInputStream doesn't actually close the stream. But again this works for tar archives.

I read somewhere that one can manage to delete ZIP archives calling listFiles() on the parent file and locating the ZIP archive and deleting it, but this sounds like a weird convoluted process. There must be some simpler way.

EDIT:

The problem is specific to Windows. On Linux (SliTaz 4 and Red Hat Enterprise 5) this works perfectly fine. This tells me that Windows is somehow locking the ZIP archives, which seems a bit strange.

Sardtok
  • 449
  • 7
  • 18
  • You should use `try-finally` statements to ensure stream closure occurs in the event of an exception. – FThompson Feb 03 '13 at 17:48
  • Check for `.mkdirs()` and friends, they may fail silently -- which is why you should also use the `Files` API if you use Java 7 instead of `File`. – fge Feb 03 '13 at 17:55
  • @Vulcan I switched it to try with resources. But no difference. @fge Using `Files` and `Path`, it tells me that the file is in use by another process (which could very well mean the program itself). But even using `deleteOnExit` has no effect, which makes it seem to me the file might be in use by the OS (I'm running it on Windows right now, but I'll try it on Linux tomorrow). If `mkdirs` fails or I remove it, I get I/O exceptions on the files that are created upon extraction. – Sardtok Feb 03 '13 at 22:11
  • This problem is specific to versions of Windows prior to Windows 8 it seems. It works perfectly fine after I have upgraded from Windows 7 to Windows 8.1 (haven't tested prior to the 8 to 8.1 update). – Sardtok Feb 03 '14 at 00:51
  • 1
    This is a pretty common problem on Windows in general. It takes a bit of time before you can delete a file after invoking close and may even require a garbage collector cycle. This has lead to workarounds like `tryHardToDelete` in Ant's `FileUtils` https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/util/FileUtils.java#L1569 – Stefan Bodewig Feb 08 '15 at 20:40
  • The issue has shown up once in a while since the upgrade to Windows 8.1. I'll try something like the above. Since I'm working with a large number of archives, I can probably just put references to all archives that should be deleted in a list, do a garbage collection after decompression, and then run through the list and try to delete the files. Maybe you could convert the comment to an answer? – Sardtok Feb 09 '15 at 08:24

1 Answers1

3

Unfortunately it is quite common that files belonging to streams you have closed just now cannot be deleted on Windows. Sometimes you need to wait a little and sometimes even that is not enough and you need a garbage collection cycle.

For example this has lead to Ant's FileUtils#tryHardToDelete https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/util/FileUtils.java#L1569 - and even that is known to sometimes leave files dangling, in which case File#deleteOnExec is your best bet.

Stefan Bodewig
  • 3,260
  • 15
  • 22