Unjar a file : Jar File « File Input Output « Java






Unjar a file

  

/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;

/** A utility class for dealing with Jar files.

@author Scott.Stark@jboss.org
@version $Revision: 2787 $
*/
public final class JarUtils
{
   /**
    * Hide the constructor
    */
   private JarUtils()
   {
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.</P>
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, new File[] { src }, null, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File src) throws IOException
   {
      jar(out, new File[] { src }, null, null, null);
   }
 
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.</P>
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, src, null, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src) throws IOException
   {
      jar(out, src, null, null, null);
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.  Directories are processed recursively, applying the
    * specified filter if it exists.
    *
    * <P>This is a shortcut for<br>
    * <code>jar(out, src, filter, null, null);</code></P>
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @param filter The filter to use while processing directories.  Only
    *        those files matching will be included in the jar archive.  If
    *        null, then all files are included.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src, FileFilter filter)
      throws IOException
   {
      jar(out, src, filter, null, null);
   }
   
   /**
    * <P>This function will create a Jar archive containing the src
    * file/directory.  The archive will be written to the specified
    * OutputStream.  Directories are processed recursively, applying the
    * specified filter if it exists.
    *
    * @param out The output stream to which the generated Jar archive is
    *        written.
    * @param src The file or directory to jar up.  Directories will be
    *        processed recursively.
    * @param filter The filter to use while processing directories.  Only
    *        those files matching will be included in the jar archive.  If
    *        null, then all files are included.
    * @param prefix The name of an arbitrary directory that will precede all
    *        entries in the jar archive.  If null, then no prefix will be
    *        used.
    * @param man The manifest to use for the Jar archive.  If null, then no
    *        manifest will be included.
    * @throws IOException 
    */
   public static void jar(OutputStream out, File[] src, FileFilter filter,
      String prefix, Manifest man) throws IOException
   {
      
      for (int i = 0; i < src.length; i++)
      {
         if (!src[i].exists())
         {
            throw new FileNotFoundException(src.toString());
         }
      }
      
      JarOutputStream jout;
      if (man == null)
      {
         jout = new JarOutputStream(out);
      }
      else
      {
         jout = new JarOutputStream(out, man);
      }
      if (prefix != null && prefix.length() > 0 && !prefix.equals("/"))
      {
         // strip leading '/'
         if (prefix.charAt(0) == '/')
         {
            prefix = prefix.substring(1);
         }
         // ensure trailing '/'
         if (prefix.charAt(prefix.length() - 1) != '/')
         {
            prefix = prefix + "/";
         }
      } 
      else
      {
         prefix = "";
      }
      JarInfo info = new JarInfo(jout, filter);
      for (int i = 0; i < src.length; i++)
      {
         jar(src[i], prefix, info);
      }
      jout.close();
   }
   
   /**
    * This simple convenience class is used by the jar method to reduce the
    * number of arguments needed.  It holds all non-changing attributes
    * needed for the recursive jar method.
    */
   private static class JarInfo
   {
      public JarOutputStream out;
      public FileFilter filter;
      public byte[] buffer;
      
      public JarInfo(JarOutputStream out, FileFilter filter)
      {
         this.out = out;
         this.filter = filter;
         buffer = new byte[1024];
      }
   }
   
   /**
    * This recursive method writes all matching files and directories to
    * the jar output stream.
    */
   private static void jar(File src, String prefix, JarInfo info)
      throws IOException
   {
      
      JarOutputStream jout = info.out;
      if (src.isDirectory())
      {
         // create / init the zip entry
         prefix = prefix + src.getName() + "/";
         ZipEntry entry = new ZipEntry(prefix);
         entry.setTime(src.lastModified());
         entry.setMethod(JarOutputStream.STORED);
         entry.setSize(0L);
         entry.setCrc(0L);
         jout.putNextEntry(entry);
         jout.closeEntry();
         
         // process the sub-directories
         File[] files = src.listFiles(info.filter);
         for (int i = 0; i < files.length; i++)
         {
            jar(files[i], prefix, info);
         }
      } 
      else if (src.isFile())
      {
         // get the required info objects
         byte[] buffer = info.buffer;
         
         // create / init the zip entry
         ZipEntry entry = new ZipEntry(prefix + src.getName());
         entry.setTime(src.lastModified());
         jout.putNextEntry(entry);
         
         // dump the file
         FileInputStream in = new FileInputStream(src);
         int len;
         while ((len = in.read(buffer, 0, buffer.length)) != -1)
         {
            jout.write(buffer, 0, len);
         }
         in.close();
         jout.closeEntry();
      }
   }
   
   public static void unjar(InputStream in, File dest) throws IOException
   {
      if (!dest.exists())
      {
         dest.mkdirs();
      }
      if (!dest.isDirectory())
      {
         throw new IOException("Destination must be a directory.");
      }
      JarInputStream jin = new JarInputStream(in);
      byte[] buffer = new byte[1024];
      
      ZipEntry entry = jin.getNextEntry();
      while (entry != null)
      {
         String fileName = entry.getName();
         if (fileName.charAt(fileName.length() - 1) == '/')
         {
            fileName = fileName.substring(0, fileName.length() - 1);
         }
         if (fileName.charAt(0) == '/')
         {
            fileName = fileName.substring(1);
         }
         if (File.separatorChar != '/')
         {
            fileName = fileName.replace('/', File.separatorChar);
         }
         File file = new File(dest, fileName);
         if (entry.isDirectory())
         {
            // make sure the directory exists
            file.mkdirs();
            jin.closeEntry();
         } 
         else
         {
            // make sure the directory exists
            File parent = file.getParentFile();
            if (parent != null && !parent.exists())
            {
               parent.mkdirs();
            }
            
            // dump the file
            OutputStream out = new FileOutputStream(file);
            int len = 0;
            while ((len = jin.read(buffer, 0, buffer.length)) != -1)
            {
               out.write(buffer, 0, len);
            }
            out.flush();
            out.close();
            jin.closeEntry();
            file.setLastModified(entry.getTime());
         }
         entry = jin.getNextEntry();
      }
      /* Explicity write out the META-INF/MANIFEST.MF so that any headers such
      as the Class-Path are see for the unpackaged jar
      */
      Manifest mf = jin.getManifest();
      if (mf != null)
      {
         File file = new File(dest, "META-INF/MANIFEST.MF");
         File parent = file.getParentFile();
         if( parent.exists() == false )
         {
            parent.mkdirs();
         }
         OutputStream out = new FileOutputStream(file);
         mf.write(out);
         out.flush();
         out.close();
      }
      jin.close();
   }

   /** Given a URL check if its a jar url(jar:<url>!/archive) and if it is,
    extract the archive entry into the given dest directory and return a file
    URL to its location. If jarURL is not a jar url then it is simply returned
    as the URL for the jar.

    @param jarURL the URL to validate and extract the referenced entry if its
      a jar protocol URL
    @param dest the directory into which the nested jar will be extracted.
    @return the file: URL for the jar referenced by the jarURL parameter.
    * @throws IOException 
    */
   public static URL extractNestedJar(URL jarURL, File dest)
      throws IOException
   {
      // This may not be a jar URL so validate the protocol 
      if( jarURL.getProtocol().equals("jar") == false )
         return jarURL;

      String destPath = dest.getAbsolutePath();
      URLConnection urlConn = jarURL.openConnection();
      JarURLConnection jarConn = (JarURLConnection) urlConn;
      // Extract the archive to dest/jarName-contents/archive
      String parentArchiveName = jarConn.getJarFile().getName();
      // Find the longest common prefix between destPath and parentArchiveName
      int length = Math.min(destPath.length(), parentArchiveName.length());
      int n = 0;
      while( n < length )
      {
         char a = destPath.charAt(n);
         char b = parentArchiveName.charAt(n);
         if( a != b )
            break;
         n ++;
      }
      // Remove any common prefix from parentArchiveName
      parentArchiveName = parentArchiveName.substring(n);

      File archiveDir = new File(dest, parentArchiveName+"-contents");
      if( archiveDir.exists() == false && archiveDir.mkdirs() == false )
         throw new IOException("Failed to create contents directory for archive, path="+archiveDir.getAbsolutePath());
      String archiveName = jarConn.getEntryName();
      File archiveFile = new File(archiveDir, archiveName);
      File archiveParentDir = archiveFile.getParentFile();
      if( archiveParentDir.exists() == false && archiveParentDir.mkdirs() == false )
         throw new IOException("Failed to create parent directory for archive, path="+archiveParentDir.getAbsolutePath());
      InputStream archiveIS = jarConn.getInputStream();
      FileOutputStream fos = new FileOutputStream(archiveFile);
      BufferedOutputStream bos = new BufferedOutputStream(fos);
      byte[] buffer = new byte[4096];
      int read;
      while( (read = archiveIS.read(buffer)) > 0 )
      {
         bos.write(buffer, 0, read);
      }
      archiveIS.close();
      bos.close();

      // Return the file url to the extracted jar
      return archiveFile.toURL();
   }


   public static void main(String[] args) throws Exception
   {
      if (args.length == 0)
      {
         System.out.println("usage: <x or c> <jar-archive> <files...>");
         System.exit(0);
      }
      if (args[0].equals("x"))
      {
         BufferedInputStream in = new BufferedInputStream(new FileInputStream(args[1]));
         File dest = new File(args[2]);
         unjar(in, dest);
      }
      else if (args[0].equals("c"))
      {
         BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(args[1]));
         File[] src = new File[args.length - 2];
         for (int i = 0; i < src.length; i++)
         {
            src[i] = new File(args[2 + i]);
         }
         jar(out, src);
      }
      else
      {
         System.out.println("Need x or c as first argument");
      }
   }
}

   
    
  








Related examples in the same category

1.Load an Image from a JAR file
2.List files in a jar file
3.Reading a text file from a jar file without unzipping
4.Load an Icon from a jar
5.Creating a JAR File
6.Sign jar with the certificate named alias in the keystore
7.JAR Archives: Jar Lister
8.JAR Archives: Packer200
9.JAR Archives: Unpacker200
10.Listing the Entries of a JAR File Manifest
11.Listing the Main Attributes in a JAR File Manifest
12.Retrieves the manifest from a JAR file and writes the manifest contents to a file.
13.Create Jar file
14.Get the jar file from a URL
15.Get the jar file
16.Get the jar entry
17.Getting a Jar File Using a URL
18.When no entry is specified on the URL, the entry name is null
19.Get the entry name; it should be the same as specified on URL
20.Manifest Writer
21.Load resource from Jar file
22.Jar Entry OutputStream
23.Helper Class to manipulate Java Archive File
24.Search all jar and zip files in the current directory for a given class file
25.Some utility classes for manipulating JAR files
26.Retreive Text File From Jar
27.Retreive Binary File From Jar
28.Zip jar Imploder
29.InstallJars - a utility to download and install files, Jars and Zips.
30.Get resource from Jar file
31.class for exploding jar/zip files onto the file system
32.Create a URL that refers to a jar file in the file system
33.Create a URL that refers to an entry in the jar file
34.Jar file helper to deployment
35.Make Temp Jar
36.Determine whether a file is a JAR File.
37.Search class in class path and Jar files
38.Add a jar entry to the deployment archive
39.Add jar contents to the deployment archive under the given prefix
40.Jarring and unjarring files and directories.
41.Create a Jar archive containing the src file/directory
42.A class to find resources in the classpath by their mime-type specified in the MANIFEST.
43.Jar builder
44.Writes all files of the given directory to the specified jar-file