/* * @(#) JarFileReader.java 1.00 2004/09/20 * * (c) Copyright 2004 OPENSOURCE ORGANIZATION * * FILENAME : JarFileReader.java * PACKAGE : org.opensource.study.jar * CREATE DATE : 2004/09/20 * AUTHOR : Humx (humx_hn@hotmail.com) * MODIFIED BY : * DESCRIPTION : a class read all entry from certain file * you are free to use and modify it. */
package org.opensource.study.jar.util;
import java.io.IOException; import java.io.File; import java.io.InputStream; import java.io.BufferedInputStream; import java.io.OutputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.util.Enumeration; import java.util.Map; import java.util.HashMap; import java.util.Set; import java.util.HashSet; import java.util.Iterator; import java.util.jar.JarEntry; import java.util.jar.JarFile;
/** * a simple class to read entry from jar file or directory * default it will read the entries from the nested jar | war file, * you can this behavior by setRecursive(false), all the entry will * be in a set.<br> * <b>Attention:</b> the duplicated entry name will ignored. * @author Hu mingxin * @version 1.0 */ public final class FileReader {
private Set suffix = null;
/** * default constructor without argument, * default, the file with suffix: ".jar" and ".war" will * be read out recursively */ public FileReader() { suffix = new HashSet(); suffix.add(".jar"); suffix.add(".war"); }
/** * specifies the suffix of the file * @param suffix the set contains the suffix of the zip file * which should be uncompress and analyse, it means this * process is done recursively, the entry in the set should * be String instance.<br> * for example:<br> * zipSet = {".jar", ".war"}; */ public FileReader(Set suffix) { this.suffix = suffix; }
/** * read all the entries in the file, file may be a jar | war file * or a directory, you can set the suffix of the file which one in * the directory or jar | war file should be read recursively * @param file the file or directory you want to process * @return set it contains all the entries in the directory or jar * file, maybe include entries from the nested jar | war files. * @throws java.io.IOException if an I/O error has occurred * @see #FileReader(Set suffix) */ public Set read(File file) throws IOException { Set entries = new HashSet(); read(file, entries, false); return entries; }
/** * comparatively, this method has a parameter surface, if false, * this method's behavior is the same to read(File file). * on the contrary, the returned set ony contain the entries of * the surface. if it's a directory, all files in it will be scaned * recursively; jar | war file will only list the entry in this zip * file, if there are jar | zip file entries, they will not be read * recursively * @param file the file or directory you want to process * @return set it contains all the entries in the directory or jar * file, if surface is true, entries nested jar | war file will * not be contained * @throws java.io.IOException if an I/O error has occurred * @see #read(File file) */ public Set read(File file, boolean surface) throws IOException { if (surface) { // if file is a directory, all entries should be // read out but only jar | war file name is traced Set entries = new HashSet(); if (file.isDirectory()) { read(file, entries, true); } else { JarFile jarFile = new JarFile(file); read(jarFile, entries, false); } return entries; } return read(file); }
/** * read the entries into entrySet of certain File * @param file the file you analyse * @param entrySet the set of the entries * @param ignoreJar if true when jar | war file is encountered * only the entry name of it will be add into the set. * otherwise, jar | war entry will be retrieved recresively * @throws java.io.IOException if an I/O error has occurred */ private void read(File file, Set entrySet, boolean ignoreJar) throws IOException { String name = file.getName(); if (file.isDirectory()) { File[] files = file.listFiles(); for (int i = 0; i < files.length; i++) { read(files[i], entrySet, ignoreJar); } } else if (isRecursiveZip(name) && !ignoreJar) { JarFile entry = new JarFile(file); read(entry, entrySet, true); } else { entrySet.add(file.getPath()); } }
/** * read the entries into entrySet of certain JarFile * @param jarFile the jarFile you care about * @param entrySet the set of the entries * @param recursive if true, the entries in the nested jar | war * file will also be retrieved and added into entrySet * @throws java.io.IOException if an I/O error has occurred */ private void read(JarFile jarFile, Set entrySet, boolean recursive) throws IOException { for (Enumeration e = jarFile.entries(); e.hasMoreElements(); ) { JarEntry jarEntry = (JarEntry)e.nextElement();
if (jarEntry.isDirectory()) { continue; }
String entryName = jarEntry.getName(); if (isRecursiveZip(entryName) && recursive) { JarFile innerJarFile = getJarFile(jarFile, jarEntry); read(innerJarFile, entrySet, recursive); } else { if (!entrySet.add(entryName)) { // a duplicated entry [" + entryName + "] has been ignored"; } } } }
/** * get teh JarFile reference from the entry[jar | war] from centain * JarFile, in other words, the inner jar | war file are uncompressed * and it's reference is returned * @param jarFile the jarFile you analyse * @param jarEntry the zip entry of the jarFile * @return jarEntry's JarFile reference * @throws java.io.IOException if an I/O error has occurred */ private JarFile getJarFile(JarFile jarFile, JarEntry jarEntry) throws IOException { // read jar entry into a byte array InputStream in = new BufferedInputStream(jarFile.getInputStream(jarEntry));
// write these bytes into a file File temporary = File.createTempFile("clazzjarfile", ".jar"); OutputStream out = new BufferedOutputStream(new FileOutputStream(temporary));
int len; byte[] buf = new byte[1024]; while ((len = in.read(buf)) > 0) { out.write(buf, 0, len); }
// release resource out.flush(); out.close(); in.close();
// analyse the temporary file return new JarFile(temporary); }
/** * if a file is a jar | war file, we should care about * @param name the file's name * @return if the file has a suffix contained in suffix * true is return, else false */ private boolean isRecursiveZip(String name) { if (suffix == null) { return false; } for (Iterator i = suffix.iterator(); i.hasNext(); ) { if (name.endsWith(i.next().toString())) { return true; } } return false; } }
// TODO this FileReader will generated a lot of temporary jar file, perhaps // we should clean up all of them; 2004-9-23 07:50:15 
|