Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why it is impossible to delete entries from jar file?

Tags:

java

jar

It is possible to add new entries to jar file using jar tool.
It is possible to modify some entries in jar file using jar tool.
But it is impossible to delete some entries from jar file.
Why?

like image 655
Volodymyr Bezuglyy Avatar asked Jun 15 '10 16:06

Volodymyr Bezuglyy


3 Answers

Noone really answered the original Why? question, answers just contain tips how to still do it.

So Why?

Jar and zip files are compressed files having a set of files or directores commonly referred to as entries. The structure/format of jar/zip files is a sequencial enumeration of entries (besides a zip file format header).

Each entry has a header which contains info about the entry, e.g. its name, type, its byte-length (and others).

Now taking this sequential entry list, how would you go about deleting an entry from the middle of the file? It would leave a "hole" in the middle of the file. The only way to delete an entry (without having to re-create the archive without the deletable entry) would require to copy the zip file content starting after the entry to the beginning of the current (deletable) entry, and also truncating the zip file length by the length of the deleted entry.

Imagine what this would mean if you have an archive with tens or hundreds of MBs? If you would delete an entry at the beginning, you would have to copy almost the whole content of the file a few bytes (or kilobytes) back in order not to leave a gap in the file.

So that's why.

This structure allows to easily add new entries because they can be appended to the end of the file easily, but (entry) delete cannot be performed effectively.

like image 120
icza Avatar answered Nov 03 '22 00:11

icza


Why?

Probably since the jar command is similar to the unix command tar. Both are to create archives and not intended to manage them.

Alteratives:

  • If you need to twiddle manually simply use a tool like 7-zip.
  • If you want to (re)create jar's programmatically ant is your friend
like image 20
stacker Avatar answered Nov 02 '22 23:11

stacker


The intent of a jar file is to package a Java Application. There is really no need to delete entries as you are packaging an application for deployment.

Here are three possible ways you could do it.

  1. You can use winzip or some other zip utility
  2. You can just use jar with the proper entries (Delete the jar and repackage).
  3. You can do it programatically...

...sort of, see below:

import java.io.*;
import java.util.*;
import java.util.zip.*;
import java.util.jar.*;


public class JarUpdate
{
    /**
     * main()
     */
    public static void main(String[] args) throws IOException
    {
        // Get the jar name and entry name from the command-line.

        String jarName = args[0];
        String fileName = args[1];

        // Create file descriptors for the jar and a temp jar.

        File jarFile = new File(jarName);
        File tempJarFile = new File(jarName + ".tmp");

        // Open the jar file.

        JarFile jar = new JarFile(jarFile);
        System.out.println(jarName + " opened.");

        // Initialize a flag that will indicate that the jar was updated.

        boolean jarUpdated = false;

        try
        {
            // Create a temp jar file with no manifest. (The manifest will
            // be copied when the entries are copied.)

            Manifest jarManifest = jar.getManifest();
            JarOutputStream tempJar = new JarOutputStream(new FileOutputStream(tempJarFile));

            // Allocate a buffer for reading entry data.

            byte[] buffer = new byte[1024];
            int bytesRead;

            try
            {
                // Open the given file.

                FileInputStream file = new FileInputStream(fileName);

                try
                {
                    // Create a jar entry and add it to the temp jar.

                    JarEntry entry = new JarEntry(fileName);
                    tempJar.putNextEntry(entry);

                    // Read the file and write it to the jar.

                    while ((bytesRead = file.read(buffer)) != -1)
                    {
                        tempJar.write(buffer, 0, bytesRead);
                    }

                    System.out.println(entry.getName() + " added.");
                }
                finally
                {
                    file.close();
                }

                // Loop through the jar entries and add them to the temp jar,
                // skipping the entry that was added to the temp jar already.

                for (Enumeration entries = jar.entries(); entries.hasMoreElements();)
                {
                    // Get the next entry.

                    JarEntry entry = (JarEntry)entries.nextElement();

                    // If the entry has not been added already, add it.

                    if (!entry.getName().equals(fileName))
                    {
                        // Get an input stream for the entry.

                        InputStream entryStream = jar.getInputStream(entry);

                        // Read the entry and write it to the temp jar.

                        tempJar.putNextEntry(entry);

                        while ((bytesRead = entryStream.read(buffer)) != -1)
                        {
                            tempJar.write(buffer, 0, bytesRead);
                        }
                    }
                }

                jarUpdated = true;
            }
            catch (Exception ex)
            {
                System.out.println(ex);

                // Add a stub entry here, so that the jar will close without an
                // exception.

                tempJar.putNextEntry(new JarEntry("stub"));
            }
            finally
            {
                tempJar.close();
            }
        }
        finally
        {
            jar.close();
            System.out.println(jarName + " closed.");

            // If the jar was not updated, delete the temp jar file.

            if (!jarUpdated)
            {
                tempJarFile.delete();
            }
        }

        // If the jar was updated, delete the original jar file and rename the
        // temp jar file to the original name.

        if (jarUpdated)
        {
            jarFile.delete();
            tempJarFile.renameTo(jarFile);
            System.out.println(jarName + " updated.");
        }
    }
}
like image 36
Romain Hippeau Avatar answered Nov 02 '22 23:11

Romain Hippeau